fixes: add tests for generation and fix some situation

This commit is contained in:
Julien Fastré 2023-05-31 23:29:34 +02:00
parent 1b0569c974
commit 80dfa092db
Signed by: julienfastre
GPG Key ID: BDE2190974723FCB
8 changed files with 503 additions and 37 deletions

View File

@ -206,10 +206,10 @@ class ActivityContext implements
$normalized = [];
foreach (['mainPerson', 'person1', 'person2'] as $k) {
$normalized[$k] = null === $data[$k] ? null : $data[$k]->getId();
$normalized[$k] = ($data[$k] ?? null)?->getId();
}
$normalized['thirdParty'] = null === $data['thirdParty'] ? null : $data['thirdParty']->getId();
$normalized['thirdParty'] = ($data['thirdParty'] ?? null)?->getId();
return $normalized;
}

View File

@ -44,6 +44,7 @@ use Symfony\Contracts\Translation\TranslatorInterface;
use function array_key_exists;
/**
* @see AccompanyingPeriodContextTest
* @template-implements DocGeneratorContextWithPublicFormInterface<AccompanyingPeriod>
*/
class AccompanyingPeriodContext implements
@ -116,12 +117,11 @@ class AccompanyingPeriodContext implements
'person2' => $data['person2'] ?? false,
'person2Label' => $data['person2Label'] ?? $this->translator->trans('docgen.person 2'),
'thirdParty' => $data['thirdParty'] ?? false,
'thirdPartyLabel' => $data['thirdPartyLabel'] ?? $this->translator->trans('thirdParty'),
'thirdPartyLabel' => $data['thirdPartyLabel'] ?? $this->translator->trans('Third party'),
];
if (array_key_exists('category', $data)) {
$r['category'] = array_key_exists('category', $data) ?
$this->documentCategoryRepository->find($data['category']) : null;
$r['category'] = $this->documentCategoryRepository->find($data['category']);
}
return $r;
@ -214,17 +214,15 @@ class AccompanyingPeriodContext implements
}
$thirdParties = array_merge(
array_filter(array_values([$entity->getRequestorThirdParty()])),
array_filter(
array_values(
array_map(
fn (Resource $r): ?ThirdParty => $r->getThirdParty(),
$entity->getResources()->filter(
static fn (Resource $r): bool => null !== $r->getThirdParty()
)->toArray()
)
array_values(array_filter([$entity->getRequestorThirdParty()])),
array_values(array_filter(
array_map(
fn (Resource $r): ?ThirdParty => $r->getThirdParty(),
$entity->getResources()->filter(
static fn (Resource $r): bool => null !== $r->getThirdParty()
)->toArray()
)
)
))
);
if ($options['thirdParty'] ?? false) {
@ -320,7 +318,7 @@ class AccompanyingPeriodContext implements
$normalized[$k] = null !== ($data[$k] ?? null) ? $data[$k]->getId() : null;
}
$normalized['thirdParty'] = null === $data['thirdParty'] ? null : $data['thirdParty']->getId();
$normalized['thirdParty'] = ($data['thirdParty'] ?? null)?->getId();
return $normalized;
}

View File

@ -117,10 +117,10 @@ class AccompanyingPeriodWorkEvaluationContext implements
$this->accompanyingPeriodWorkContext->buildPublicForm($builder, $template, $entity->getAccompanyingPeriodWork());
$thirdParties = array_merge(
array_filter(array_values($entity->getAccompanyingPeriodWork()->getThirdParties()->toArray())),
array_filter(array_values([$entity->getAccompanyingPeriodWork()->getHandlingThierParty()])),
array_filter(
array_values(
array_values(array_filter($entity->getAccompanyingPeriodWork()->getThirdParties()->toArray())),
array_values(array_filter([$entity->getAccompanyingPeriodWork()->getHandlingThierParty()])),
array_values(
array_filter(
array_map(
fn (Resource $r): ?ThirdParty => $r->getThirdParty(),
$entity->getAccompanyingPeriodWork()->getAccompanyingPeriod()->getResources()->filter(

View File

@ -38,6 +38,7 @@ use DateTime;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository;
use LogicException;
use Service\DocGenerator\PersonContextTest;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
@ -50,6 +51,9 @@ use Symfony\Contracts\Translation\TranslatorInterface;
use function array_key_exists;
use function count;
/**
* @see PersonContextTest
*/
final class PersonContext implements PersonContextInterface
{
private AuthorizationHelperInterface $authorizationHelper;
@ -130,12 +134,11 @@ final class PersonContext implements PersonContextInterface
'mainPerson' => $data['mainPerson'] ?? false,
'mainPersonLabel' => $data['mainPersonLabel'] ?? $this->translator->trans('docgen.Main person'),
'thirdParty' => $data['thirdParty'] ?? false,
'thirdPartyLabel' => $data['thirdPartyLabel'] ?? $this->translator->trans('thirdParty'),
'thirdPartyLabel' => $data['thirdPartyLabel'] ?? $this->translator->trans('Third party'),
];
if (array_key_exists('category', $data)) {
$r['category'] = array_key_exists('category', $data) ?
$this->documentCategoryRepository->find($data['category']) : null;
$r['category'] = $this->documentCategoryRepository->find($data['category']);
}
return $r;
@ -177,8 +180,8 @@ final class PersonContext implements PersonContextInterface
]);
$thirdParties = array_merge(
array_filter(
array_values(
array_values(
array_filter(
array_map(
fn (ResidentialAddress $r): ?ThirdParty => $r->getHostThirdParty(),
$this
@ -187,8 +190,8 @@ final class PersonContext implements PersonContextInterface
)
)
),
array_filter(
array_values(
array_values(
array_filter(
array_map(
fn (PersonResource $r): ?ThirdParty => $r->getThirdParty(),
$entity->getResources()->filter(
@ -223,10 +226,6 @@ final class PersonContext implements PersonContextInterface
public function getData(DocGeneratorTemplate $template, $entity, array $contextGenerationData = []): array
{
if (!$entity instanceof Person) {
throw new UnexpectedTypeException($entity, Person::class);
}
$data = [];
$data = array_merge($data, $this->baseContextData->getData($contextGenerationData['creator'] ?? null));
$data['person'] = $this->normalizer->normalize($entity, 'docgen', [
@ -297,7 +296,7 @@ final class PersonContext implements PersonContextInterface
return [
'title' => $data['title'] ?? '',
'scope_id' => $scope instanceof Scope ? $scope->getId() : null,
'thirdParty' => null === $data['thirdParty'] ? null : $data['thirdParty']->getId(),
'thirdParty' => ($data['thirdParty'] ?? null)?->getId(),
];
}

View File

@ -19,7 +19,8 @@ use Chill\PersonBundle\Entity\Person;
use Symfony\Component\Form\FormBuilderInterface;
/**
* @template-extends DocGeneratorContextWithPublicFormInterface<Person>
* @template-extends DocGeneratorContextWithPublicFormInterface<Person>
* @template-extends DocGeneratorContextWithAdminFormInterface<Person>
*/
interface PersonContextInterface extends DocGeneratorContextWithAdminFormInterface, DocGeneratorContextWithPublicFormInterface
{

View File

@ -0,0 +1,291 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Service\DocGenerator;
use Chill\DocGeneratorBundle\Entity\DocGeneratorTemplate;
use Chill\DocGeneratorBundle\Service\Context\BaseContextData;
use Chill\DocStoreBundle\Repository\DocumentCategoryRepository;
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\Person;
use Chill\PersonBundle\Repository\PersonRepository;
use Chill\PersonBundle\Service\DocGenerator\AccompanyingPeriodContext;
use Chill\PersonBundle\Templating\Entity\PersonRenderInterface;
use Chill\ThirdPartyBundle\Entity\ThirdParty;
use Chill\ThirdPartyBundle\Repository\ThirdPartyRepository;
use Chill\ThirdPartyBundle\Templating\Entity\ThirdPartyRender;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
/**
* @internal
* @coversNothing
*/
class AccompanyingPeriodContextTest extends KernelTestCase
{
private BaseContextData $baseContextData;
private DocumentCategoryRepository $documentCategoryRepository;
private EntityManagerInterface $em;
private NormalizerInterface $normalizer;
private PersonRenderInterface $personRender;
private PersonRepository $personRepository;
private TranslatableStringHelperInterface $translatableStringHelper;
private TranslatorInterface $translator;
private ThirdPartyRender $thirdPartyRender;
private ThirdPartyRepository $thirdPartyRepository;
protected function setUp(): void
{
self::bootKernel();
$this->baseContextData = self::$container->get(BaseContextData::class);
$this->documentCategoryRepository = self::$container->get(DocumentCategoryRepository::class);
$this->em = self::$container->get(EntityManagerInterface::class);
$this->normalizer = self::$container->get(NormalizerInterface::class);
$this->personRender = self::$container->get(PersonRenderInterface::class);
$this->personRepository = self::$container->get(PersonRepository::class);
$this->translatableStringHelper = self::$container->get(TranslatableStringHelperInterface::class);
$this->translator = self::$container->get(TranslatorInterface::class);
$this->thirdPartyRender = self::$container->get(ThirdPartyRender::class);
$this->thirdPartyRepository = self::$container->get(ThirdPartyRepository::class);
}
private function buildContext(): AccompanyingPeriodContext
{
return new AccompanyingPeriodContext(
$this->documentCategoryRepository,
$this->normalizer,
$this->translatableStringHelper,
$this->em,
$this->personRender,
$this->personRepository,
$this->translator,
$this->baseContextData,
$this->thirdPartyRender,
$this->thirdPartyRepository,
);
}
/**
* This test run the methods executed when a document is generated:
*
* - normalized data from the form in a way that they are stored in message queue;
* - denormalize the data from the message queue,
* - and get the data, as they will be transmitted to the GeneratorDriver
*
* @param array $options the options, as they are stored in the DocGeneratorTemplate (the admin form data)
* @param AccompanyingPeriod $entity The entity from which the data will be extracted
* @param array $data The data, from the public form
* @param array $expectedNormalized, how the normalized data are expected (allow to check that this data will be compliant with the storage in messenger queue)
* @param callable $assertionsOnData some test that will be executed on the normalized data
* @dataProvider provideNormalizedData
*/
public function testContextGenerationDataNormalizeDenormalizeGetData(
array $options,
AccompanyingPeriod $entity,
array $data,
array $expectedNormalized,
callable $assertionsOnData
): void {
$context = $this->buildContext();
$template = new DocGeneratorTemplate();
$template->setName(["fr" =>"test"])->setContext(AccompanyingPeriodContext::class)
->setDescription("description")->setActive(true)
->setOptions($options);
$normalized = $context->contextGenerationDataNormalize($template, $entity, $data);
self::assertEquals($expectedNormalized, $normalized);
$denormalized = $context->contextGenerationDataDenormalize($template, $entity, $normalized);
$data = $context->getData($template, $entity, $denormalized);
call_user_func($assertionsOnData, $data);
}
public function provideNormalizedData(): iterable
{
self::bootKernel();
$em = self::$container->get(EntityManagerInterface::class);
$thirdParty = $em->createQuery("SELECT t FROM " . ThirdParty::class . " t")
->setMaxResults(1)
->getSingleResult();
if (null === $thirdParty) {
throw new \RuntimeException("No thirdparty in database");
}
$period = $em->createQuery("SELECT a FROM " . AccompanyingPeriod::class . " a WHERE a.step = 'CONFIRMED'")
->setMaxResults(1)
->getSingleResult();
if (null === $period) {
throw new \RuntimeException("No confirmed period in database");
}
$person = $em->createQuery("SELECT p FROM " . Person::class . " p")
->setMaxResults(1)
->getSingleResult();
if (null === $person) {
throw new \RuntimeException("No confirmed period in database");
}
yield [
// test with only thirdParty
[
'mainPerson' => false,
'mainPersonLabel' => 'person',
'person1' => false,
'person1Label' => 'person2',
'person2' => false,
'person2Label' => 'person2',
'thirdParty' => true,
'thirdPartyLabel' => '3party'
],
$period,
[
'thirdParty' => $thirdParty
],
[
'thirdParty' => $thirdParty->getId(),
'mainPerson' => null,
'person1' => null,
'person2' => null,
],
function (array $data) use ($thirdParty, $period) {
self::assertArrayHasKey('thirdParty', $data);
self::assertEquals($thirdParty->getId(), $data['thirdParty']['id']);
self::assertArrayHasKey('course', $data);
self::assertEquals($period->getId(), $data['course']['id']);
},
];
yield [
// test with only mainPerson
[
'mainPerson' => true,
'mainPersonLabel' => 'person',
'person1' => false,
'person1Label' => 'person2',
'person2' => false,
'person2Label' => 'person2',
'thirdParty' => false,
'thirdPartyLabel' => '3party'
],
$period,
[
'mainPerson' => $person,
],
[
'thirdParty' => null,
'mainPerson' => $person->getId(),
'person1' => null,
'person2' => null,
],
function (array $data) use ($person, $period) {
self::assertArrayHasKey('mainPerson', $data);
self::assertEquals($person->getId(), $data['mainPerson']['id']);
self::assertArrayHasKey('course', $data);
self::assertEquals($period->getId(), $data['course']['id']);
},
];
yield [
// test with every options activated
[
'mainPerson' => true,
'mainPersonLabel' => 'person',
'person1' => true,
'person1Label' => 'person2',
'person2' => true,
'person2Label' => 'person2',
'thirdParty' => true,
'thirdPartyLabel' => '3party'
],
$period,
[
'mainPerson' => $person,
'person1' => $person,
'person2' => $person,
'thirdParty' => $thirdParty,
],
[
'thirdParty' => $thirdParty->getId(),
'mainPerson' => $person->getId(),
'person1' => $person->getId(),
'person2' => $person->getId(),
],
function (array $data) use ($person, $thirdParty, $period) {
self::assertArrayHasKey('mainPerson', $data);
self::assertEquals($person->getId(), $data['mainPerson']['id']);
self::assertArrayHasKey('person1', $data);
self::assertEquals($person->getId(), $data['person1']['id']);
self::assertArrayHasKey('person2', $data);
self::assertEquals($person->getId(), $data['person2']['id']);
self::assertArrayHasKey('thirdParty', $data);
self::assertEquals($thirdParty->getId(), $data['thirdParty']['id']);
self::assertArrayHasKey('course', $data);
self::assertEquals($period->getId(), $data['course']['id']);
},
];
yield [
// test with any option activated
[
'mainPerson' => false,
'mainPersonLabel' => 'person',
'person1' => false,
'person1Label' => 'person2',
'person2' => false,
'person2Label' => 'person2',
'thirdParty' => false,
'thirdPartyLabel' => '3party'
],
$period,
[
'mainPerson' => null,
'person1' => null,
'person2' => null,
'thirdParty' => null,
],
[
'thirdParty' => null,
'mainPerson' => null,
'person1' => null,
'person2' => null,
],
function (array $data) use ($period) {
self::assertArrayHasKey('course', $data);
self::assertEquals($period->getId(), $data['course']['id']);
},
];
}
}

View File

@ -18,20 +18,30 @@ use Chill\DocStoreBundle\Entity\PersonDocument;
use Chill\DocStoreBundle\Entity\StoredObject;
use Chill\DocStoreBundle\Repository\DocumentCategoryRepository;
use Chill\DocStoreBundle\Security\Authorization\PersonDocumentVoter;
use Chill\MainBundle\Entity\Address;
use Chill\MainBundle\Entity\Center;
use Chill\MainBundle\Entity\PostalCode;
use Chill\MainBundle\Entity\Scope;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Form\Type\ScopePickerType;
use Chill\MainBundle\Repository\ScopeRepositoryInterface;
use Chill\MainBundle\Security\Authorization\AuthorizationHelperInterface;
use Chill\MainBundle\Security\Resolver\CenterResolverManagerInterface;
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\Person;
use Chill\PersonBundle\Repository\ResidentialAddressRepository;
use Chill\PersonBundle\Service\DocGenerator\AccompanyingPeriodContext;
use Chill\PersonBundle\Service\DocGenerator\PersonContext;
use Chill\ThirdPartyBundle\Entity\ThirdParty;
use Chill\ThirdPartyBundle\Repository\ThirdPartyRepository;
use Chill\ThirdPartyBundle\Templating\Entity\ThirdPartyRender;
use Doctrine\ORM\EntityManagerInterface;
use PHPUnit\Framework\TestCase;
use Prophecy\Argument;
use Prophecy\Exception\Prediction\FailedPredictionException;
use Prophecy\PhpUnit\ProphecyTrait;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\Form\Extension\Core\Type\TextType;
@ -46,10 +56,142 @@ use function count;
* @internal
* @coversNothing
*/
final class PersonContextTest extends TestCase
final class PersonContextTest extends KernelTestCase
{
use ProphecyTrait;
/**
* This test run the methods executed when a document is generated:
*
* - normalized data from the form in a way that they are stored in message queue;
* - denormalize the data from the message queue,
* - and get the data, as they will be transmitted to the GeneratorDriver
*
* @param array $options the options, as they are stored in the DocGeneratorTemplate (the admin form data)
* @param Person $entity The entity from which the data will be extracted
* @param array $data The data, from the public form
* @param array $expectedNormalized, how the normalized data are expected (allow to check that this data will be compliant with the storage in messenger queue)
* @param callable $assertionsOnData some test that will be executed on the normalized data
* @dataProvider provideNormalizedData
*/
public function testContextGenerationDataNormalizeDenormalizeGetData(
array $options,
Person $entity,
array $data,
array $expectedNormalized,
callable $assertionsOnData
): void {
// we boot kernel only for this test
self::bootKernel();
// we create a PersonContext with the minimal dependency injection needed (relying on
// prophecy for other dependencies)
$context = $this->buildPersonContext(
null,
self::$container->get(BaseContextData::class),
self::$container->get(CenterResolverManagerInterface::class),
self::$container->get(DocumentCategoryRepository::class),
self::$container->get(EntityManagerInterface::class),
self::$container->get(NormalizerInterface::class),
(new ParameterBag(['chill_main' => ['acl' => ['form_show_scopes' => false]]])),
null,
self::$container->get(Security::class),
null,
null,
null,
self::$container->get(ThirdPartyRepository::class)
);
$template = new DocGeneratorTemplate();
$template->setName(["fr" =>"test"])->setContext(AccompanyingPeriodContext::class)
->setDescription("description")->setActive(true)
->setOptions($options);
$normalized = $context->contextGenerationDataNormalize($template, $entity, $data);
self::assertEquals($expectedNormalized, $normalized);
$denormalized = $context->contextGenerationDataDenormalize($template, $entity, $normalized);
$data = $context->getData($template, $entity, $denormalized);
call_user_func($assertionsOnData, $data);
}
public function provideNormalizedData(): iterable
{
self::bootKernel();
$em = self::$container->get(EntityManagerInterface::class);
$thirdParty = $em->createQuery("SELECT t FROM " . ThirdParty::class . " t")
->setMaxResults(1)
->getSingleResult();
if (null === $thirdParty) {
throw new \RuntimeException("No thirdparty in database");
}
$person = $em->createQuery("SELECT p FROM " . Person::class . " p")
->setMaxResults(1)
->getSingleResult();
if (null === $person) {
throw new \RuntimeException("No confirmed period in database");
}
$category = self::$container->get(DocumentCategoryRepository::class)
->findAll()[0];
if (null === $category) {
throw new \RuntimeException("no document category in database");
}
yield [
[
'thirdParty' => true,
'thirdPartyLabel' => '3party',
'category' => $category,
],
$person,
[
'title' => 'test',
'thirdParty' => $thirdParty,
],
[
'thirdParty' => $thirdParty->getId(),
'title' => 'test',
'scope_id' => null,
],
function ($data) use ($person, $thirdParty) {
self::assertArrayHasKey('person', $data);
self::assertEquals($person->getId(), $data['person']['id']);
self::assertArrayHasKey('thirdParty', $data);
self::assertEquals($thirdParty->getId(), $data['thirdParty']['id']);
}
];
yield [
[
'thirdParty' => false,
'thirdPartyLabel' => '3party',
'category' => $category,
],
$person,
[
'title' => 'test',
],
[
'title' => 'test',
'scope_id' => null,
'thirdParty' => null,
],
function ($data) use ($person, $thirdParty) {
self::assertArrayHasKey('person', $data);
self::assertEquals($person->getId(), $data['person']['id']);
}
];
}
/**
* Test that the build person context works in the case when 'form_show_scope' is false.
*/
@ -208,9 +350,13 @@ final class PersonContextTest extends TestCase
?EntityManagerInterface $em = null,
?NormalizerInterface $normalizer = null,
?ParameterBagInterface $parameterBag = null,
?ScopeRepositoryInterface $scopeRepository = null,
?Security $security = null,
?TranslatorInterface $translator = null,
?TranslatableStringHelperInterface $translatableStringHelper = null
?TranslatableStringHelperInterface $translatableStringHelper = null,
?ThirdPartyRender $thirdPartyRender = null,
?ThirdPartyRepository $thirdPartyRepository = null,
?ResidentialAddressRepository $residentialAddressRepository = null
): PersonContext {
if (null === $authorizationHelper) {
$authorizationHelper = $this->prophesize(AuthorizationHelperInterface::class)->reveal();
@ -250,6 +396,11 @@ final class PersonContextTest extends TestCase
$parameterBag = new ParameterBag(['chill_main' => ['acl' => ['form_show_scopes' => true]]]);
}
if (null === $scopeRepository) {
$scopeRepository = $this->prophesize(ScopeRepositoryInterface::class);
$scopeRepository = $scopeRepository->reveal();
}
if (null === $security) {
$security = $this->prophesize(Security::class);
$security->getUser()->willReturn(new User());
@ -267,6 +418,28 @@ final class PersonContextTest extends TestCase
$translatableStringHelper = $translatableStringHelper->reveal();
}
if (null === $thirdPartyRender) {
$thirdPartyRender = $this->prophesize(ThirdPartyRender::class);
$thirdPartyRender = $thirdPartyRender->reveal();
}
if (null === $thirdPartyRepository) {
$thirdPartyRepository = $this->prophesize(ThirdPartyRepository::class);
$thirdPartyRepository = $thirdPartyRepository->reveal();
}
if (null === $residentialAddressRepository) {
$residentialAddressRepository = $this->prophesize(ResidentialAddressRepository::class);
$residentialAddressRepository->findCurrentResidentialAddressByPerson(Argument::type(Person::class), Argument::any())
->willReturn([
(new Person\ResidentialAddress())
->setAddress((new Address())
->setStreet('test street')
->setPostcode(new PostalCode()))
]);
$residentialAddressRepository = $residentialAddressRepository->reveal();
}
return new PersonContext(
$authorizationHelper,
$baseContextData,
@ -275,9 +448,13 @@ final class PersonContextTest extends TestCase
$em,
$normalizer,
$parameterBag,
$scopeRepository,
$security,
$translator,
$translatableStringHelper
$translatableStringHelper,
$thirdPartyRender,
$thirdPartyRepository,
$residentialAddressRepository
);
}
}

View File

@ -21,7 +21,7 @@ use DomainException;
use function array_key_exists;
final class ThirdPartyRepository implements ObjectRepository
class ThirdPartyRepository implements ObjectRepository
{
private EntityRepository $repository;