mirror of
				https://gitlab.com/Chill-Projet/chill-bundles.git
				synced 2025-10-31 09:18:24 +00:00 
			
		
		
		
	Merge branch 'master' of https://gitlab.com/Chill-Projet/chill-bundles
This commit is contained in:
		| @@ -1,6 +0,0 @@ | ||||
| kind: DX | ||||
| body: Remove dead code for wopi-link module | ||||
| time: 2025-04-30T14:45:50.406111606+02:00 | ||||
| custom: | ||||
|     Issue: "352" | ||||
|     SchemaChange: No schema change | ||||
| @@ -1,6 +0,0 @@ | ||||
| kind: DX | ||||
| body: Replace library node-sass by sass, and upgrade bootstrap to version 5.3 (yarn upgrade / install is required) | ||||
| time: 2025-05-28T16:58:13.226870341+02:00 | ||||
| custom: | ||||
|     Issue: "" | ||||
|     SchemaChange: No schema change | ||||
| @@ -1,7 +0,0 @@ | ||||
| kind: Feature | ||||
| body: Add the document file name to the document title when a user upload a document, | ||||
|   unless there is already a document title. | ||||
| time: 2025-04-24T14:22:11.800975422+02:00 | ||||
| custom: | ||||
|   Issue: "377" | ||||
|   SchemaChange: No schema change | ||||
| @@ -1,6 +0,0 @@ | ||||
| kind: Feature | ||||
| body: Add desactivation date for social action and issue csv export | ||||
| time: 2025-05-20T09:56:28.108941934+02:00 | ||||
| custom: | ||||
|     Issue: "" | ||||
|     SchemaChange: No schema change | ||||
| @@ -1,6 +0,0 @@ | ||||
| kind: Feature | ||||
| body: Add Emoji and Fullscreen feature to ckeditor configuration | ||||
| time: 2025-05-23T13:33:41.645095128+02:00 | ||||
| custom: | ||||
|     Issue: "" | ||||
|     SchemaChange: No schema change | ||||
| @@ -1,6 +0,0 @@ | ||||
| kind: Feature | ||||
| body: Create editor which allow us to toggle between rich and simple text editor | ||||
| time: 2025-05-23T13:34:34.56795603+02:00 | ||||
| custom: | ||||
|     Issue: "321" | ||||
|     SchemaChange: No schema change | ||||
| @@ -1,7 +0,0 @@ | ||||
| kind: Fixed | ||||
| body: trying to prevent bug of typeerror in doc-history + improved display of document | ||||
|   history | ||||
| time: 2025-04-24T13:39:43.878468232+02:00 | ||||
| custom: | ||||
|   Issue: "376" | ||||
|   SchemaChange: No schema change | ||||
| @@ -1,7 +0,0 @@ | ||||
| kind: Fixed | ||||
| body: Display previous participation in acc course work even if the person has left | ||||
|   the acc course | ||||
| time: 2025-04-24T16:37:46.970203594+02:00 | ||||
| custom: | ||||
|   Issue: "381" | ||||
|   SchemaChange: No schema change | ||||
| @@ -1,6 +0,0 @@ | ||||
| kind: Fixed | ||||
| body: Fix display of text in calendar events | ||||
| time: 2025-05-05T10:27:15.461493066+02:00 | ||||
| custom: | ||||
|     Issue: "372" | ||||
|     SchemaChange: No schema change | ||||
| @@ -1,6 +0,0 @@ | ||||
| kind: Fixed | ||||
| body: Add missing translation for user_group.no_user_groups | ||||
| time: 2025-05-14T14:53:39.53927329+02:00 | ||||
| custom: | ||||
|     Issue: "" | ||||
|     SchemaChange: No schema change | ||||
| @@ -1,6 +0,0 @@ | ||||
| kind: UX | ||||
| body: Remove default filter in_progress for the page 'my tasks'; Allows for new tasks to be displayed upon opening of the page | ||||
| time: 2025-04-23T17:26:24.45777387+02:00 | ||||
| custom: | ||||
|     Issue: "374" | ||||
|     SchemaChange: No schema change | ||||
							
								
								
									
										22
									
								
								.changes/v3.12.0.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								.changes/v3.12.0.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | ||||
| ## v3.12.0 - 2025-06-30 | ||||
| ### Feature | ||||
| * ([#377](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/377)) Add the document file name to the document title when a user upload a document, unless there is already a document title.    | ||||
| * Add desactivation date for social action and issue csv export    | ||||
| * Add Emoji and Fullscreen feature to ckeditor configuration    | ||||
| * ([#321](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/321)) Create editor which allow us to toggle between rich and simple text editor    | ||||
| * Do not remove workflow which are automatically canceled after staling for more than 30 days    | ||||
| ### Fixed | ||||
| * ([#376](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/376)) trying to prevent bug of typeerror in doc-history + improved display of document history    | ||||
| * ([#381](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/381)) Display previous participation in acc course work even if the person has left the acc course    | ||||
| * ([#372](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/372)) Fix display of text in calendar events    | ||||
| * Add missing translation for user_group.no_user_groups    | ||||
| * Fix admin entity edit actions for event admin entities and activity reason (category) entities    | ||||
| * ([#392](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/392)) Allow null and cast as string to setContent method for NewsItem | ||||
|     | ||||
| * ([#393](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/393)) Doc Generation: the "dump only" method send the document as an email attachment.    | ||||
| ### DX | ||||
| * ([#352](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/352)) Remove dead code for wopi-link module    | ||||
| * Replace library node-sass by sass, and upgrade bootstrap to version 5.3 (yarn upgrade / install is required)    | ||||
| ### UX | ||||
| * ([#374](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/374)) Remove default filter in_progress for the page 'my tasks'; Allows for new tasks to be displayed upon opening of the page    | ||||
| * Improve labeling of fields in person resource creation form    | ||||
							
								
								
									
										3
									
								
								.changes/v3.12.1.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								.changes/v3.12.1.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | ||||
| ## v3.12.1 - 2025-06-30 | ||||
| ### Fixed | ||||
| * Fix loading of the list of documents    | ||||
| @@ -22,7 +22,7 @@ Chill is a comprehensive web application built as a set of Symfony bundles. It i | ||||
| - **Backend**: PHP 8.3+, Symfony 5.4 | ||||
| - **Frontend**: JavaScript/TypeScript, Vue.js 3, Bootstrap 5 | ||||
| - **Build Tools**: Webpack Encore, Yarn | ||||
| - **Database**: PostgreSQL with materialized views | ||||
| - **Database**: PostgreSQL with materialized views. We do not support other databases. | ||||
| - **Other Services**: Redis, AMQP (RabbitMQ), SMTP | ||||
|  | ||||
| ## Project Structure | ||||
| @@ -149,6 +149,42 @@ Key configuration files: | ||||
| - `package.json`: JavaScript dependencies and scripts | ||||
| - `.env`: Default environment variables. Must usually not be updated: use `.env.local` instead. | ||||
|  | ||||
| ### Database migrations | ||||
|  | ||||
| Each time a doctrine entity is created, we generate migration to adapt the database. | ||||
|  | ||||
| The migration are created using the command `symfony console doctrine:migrations:diff --no-interaction --namespace <namespace>`, where the namespace is the relevant namespace for migration. As this is a bash script, do not forget to quote the `\` (`\` must become `\\` in your command). | ||||
|  | ||||
| Each bundle has his own namespace for migration (always ask me to confirm that command, with a list of updated / created entities so that I can confirm you that it is ok): | ||||
|  | ||||
| - `Chill\Bundle\ActivityBundle` writes migrations to `Chill\Migrations\Activity`; | ||||
| - `Chill\Bundle\BudgetBundle` writes migrations to `Chill\Migrations\Budget`; | ||||
| - `Chill\Bundle\CustomFieldsBundle` writes migrations to `Chill\Migrations\CustomFields`; | ||||
| - `Chill\Bundle\DocGeneratorBundle` writes migrations to `Chill\Migrations\DocGenerator`; | ||||
| - `Chill\Bundle\DocStoreBundle` writes migrations to `Chill\Migrations\DocStore`; | ||||
| - `Chill\Bundle\EventBundle` writes migrations to `Chill\Migrations\Event`; | ||||
| - `Chill\Bundle\CalendarBundle` writes migrations to `Chill\Migrations\Calendar`; | ||||
| - `Chill\Bundle\FamilyMembersBundle` writes migrations to `Chill\Migrations\FamilyMembers`; | ||||
| - `Chill\Bundle\FranceTravailApiBundle` writes migrations to `Chill\Migrations\FranceTravailApi`; | ||||
| - `Chill\Bundle\JobBundle` writes migrations to `Chill\Migrations\Job`; | ||||
| - `Chill\Bundle\MainBundle` writes migrations to `Chill\Migrations\Main`; | ||||
| - `Chill\Bundle\PersonBundle` writes migrations to `Chill\Migrations\Person`; | ||||
| - `Chill\Bundle\ReportBundle` writes migrations to `Chill\Migrations\Report`; | ||||
| - `Chill\Bundle\TaskBundle` writes migrations to `Chill\Migrations\Task`; | ||||
| - `Chill\Bundle\ThirdPartyBundle` writes migrations to `Chill\Migrations\ThirdParty`; | ||||
| - `Chill\Bundle\TicketBundle` writes migrations to `Chill\Migrations\Ticket`; | ||||
| - `Chill\Bundle\WopiBundle` writes migrations to `Chill\Migrations\Wopi`; | ||||
|  | ||||
| Once created the, comment's classes should be removed and a description of the changes made to the entities should be added to the migrations, using the `getDescription` method. The migration should not be cleaned by any artificial intelligence, as modifying this migration is error prone. | ||||
|  | ||||
| ### Guidelines related to code structure and requirements | ||||
|  | ||||
| #### Usage of clock | ||||
|  | ||||
| When we need to use a DateTime or DateTimeImmutable that need to express "now", we prefer the usage of | ||||
| `Symfony\Component\Clock\ClockInterface`, where possible. This is usually not possible in doctrine entities, | ||||
| where injection does not work when restoring an entity from database, but usually possible in services. | ||||
|  | ||||
| ### Testing Information | ||||
|  | ||||
| The project uses PHPUnit for testing. Each bundle has its own test suite, and there's also a global test suite at the root level. | ||||
| @@ -218,7 +254,7 @@ class TicketTest extends TestCase | ||||
|  | ||||
| #### Test Database | ||||
|  | ||||
| For tests that require a database, the project uses an in-memory SQLite database by default. You can configure a different database for testing in the `.env.test` file. | ||||
| For tests that require a database, the project uses postgresql database filled by fixtures (usage of doctrine-fixtures). You can configure a different database for testing in the `.env.test` file. | ||||
|  | ||||
| ### Code Quality Tools | ||||
|  | ||||
|   | ||||
							
								
								
									
										47
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										47
									
								
								CHANGELOG.md
									
									
									
									
									
								
							| @@ -6,6 +6,53 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html), | ||||
| and is generated by [Changie](https://github.com/miniscruff/changie). | ||||
|  | ||||
|  | ||||
| ## v3.12.1 - 2025-06-30 | ||||
| ### Fixed | ||||
| * Fix loading of the list of documents    | ||||
|  | ||||
| ## v3.12.0 - 2025-06-30 | ||||
| ### Feature | ||||
| * ([#377](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/377)) Add the document file name to the document title when a user upload a document, unless there is already a document title.    | ||||
| * Add desactivation date for social action and issue csv export    | ||||
| * Add Emoji and Fullscreen feature to ckeditor configuration    | ||||
| * ([#321](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/321)) Create editor which allow us to toggle between rich and simple text editor    | ||||
| * Do not remove workflow which are automatically canceled after staling for more than 30 days    | ||||
| ### Fixed | ||||
| * ([#376](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/376)) trying to prevent bug of typeerror in doc-history + improved display of document history    | ||||
| * ([#381](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/381)) Display previous participation in acc course work even if the person has left the acc course    | ||||
| * ([#372](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/372)) Fix display of text in calendar events    | ||||
| * Add missing translation for user_group.no_user_groups    | ||||
| * Fix admin entity edit actions for event admin entities and activity reason (category) entities    | ||||
| * ([#392](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/392)) Allow null and cast as string to setContent method for NewsItem | ||||
|     | ||||
| * ([#393](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/393)) Doc Generation: the "dump only" method send the document as an email attachment.    | ||||
| ### DX | ||||
| * ([#352](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/352)) Remove dead code for wopi-link module    | ||||
| * Replace library node-sass by sass, and upgrade bootstrap to version 5.3 (yarn upgrade / install is required)    | ||||
| ### UX | ||||
| * ([#374](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/374)) Remove default filter in_progress for the page 'my tasks'; Allows for new tasks to be displayed upon opening of the page    | ||||
| * Improve labeling of fields in person resource creation form    | ||||
|  | ||||
| ## v3.11.0 - 2025-04-17 | ||||
| ### Feature | ||||
| * ([#365](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/365)) Add counters of actions and activities, with 2 boxes to (1) show the number of active actions on total actions and (2) show the number of activities in a accompanying period, and pills in menus for showing the number of active actions and the number of activities. | ||||
| * ([#364](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/364)) Added a second phone number "telephone2" to the thirdParty entity. Adapted twig templates and vuejs apps to handle this phone number | ||||
|  | ||||
|   **Schema Change**: Add columns or tables | ||||
| * Signature: add a button to go directly to the signature zone, even if there is only one | ||||
| ### Fixed | ||||
| * Fixed wrong translations in the on-the-fly for creation of thirdParty | ||||
| * Fixed update of phone number in on-the-fly edition of thirdParty | ||||
| * Fixed closing of modal when editing thirdParty in accompanying course works | ||||
| * Shorten the delay between two execution of AccompanyingPeriodStepChangeCronjob, to ensure at least one execution in a day | ||||
| * ([#102](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/102)) Fix display of title in document list | ||||
| * When cleaning the old stored object versions, do not throw an error if the stored object is not found on disk | ||||
| * Add consistent log prefix and key to logs when stale workflows are automatically canceled | ||||
| * ([#380](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/380)) Remove the "not null" validation constraint on recently added properties on HouseholdComposition | ||||
|  | ||||
| ### DX | ||||
| * Add new chill-col style for displaying title and aside in a flex table | ||||
|  | ||||
| ## v3.10.3 - 2025-03-18 | ||||
| ### DX | ||||
| * Eslint fixes    | ||||
|   | ||||
| @@ -22,6 +22,52 @@ use Symfony\Component\Security\Core\Role\Role; | ||||
|  */ | ||||
| final class ActivityControllerTest extends WebTestCase | ||||
| { | ||||
|     /** | ||||
|      * @dataProvider getSecuredPagesUnauthenticated | ||||
|      */ | ||||
|     public function testAccessIsDeniedForUnauthenticated(mixed $url) | ||||
|     { | ||||
|         $client = $this->createClient(); | ||||
|  | ||||
|         $client->request('GET', $url); | ||||
|  | ||||
|         $this->assertEquals(302, $client->getResponse()->getStatusCode()); | ||||
|         $this->assertTrue( | ||||
|             $client->getResponse()->isRedirect('http://localhost/login'), | ||||
|             sprintf('the page "%s" does not redirect to http://localhost/login', $url) | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Provide a client unauthenticated and. | ||||
|      */ | ||||
|     public function getSecuredPagesUnauthenticated() | ||||
|     { | ||||
|         self::bootKernel(); | ||||
|         $person = $this->getPersonFromFixtures(); | ||||
|         $activities = $this->getActivitiesForPerson($person); | ||||
|  | ||||
|         return [ | ||||
|             [sprintf('fr/person/%d/activity/', $person->getId())], | ||||
|             [sprintf('fr/person/%d/activity/new', $person->getId())], | ||||
|             [sprintf('fr/person/%d/activity/%d/show', $person->getId(), $activities[0]->getId())], | ||||
|             [sprintf('fr/person/%d/activity/%d/edit', $person->getId(), $activities[0]->getId())], | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider getSecuredPagesAuthenticated | ||||
|      * | ||||
|      * @param type $client | ||||
|      * @param type $url | ||||
|      */ | ||||
|     public function testAccessIsDeniedForUnauthorized($client, $url) | ||||
|     { | ||||
|         $client->request('GET', $url); | ||||
|  | ||||
|         $this->assertEquals(403, $client->getResponse()->getStatusCode()); | ||||
|     } | ||||
|  | ||||
|     public function getSecuredPagesAuthenticated() | ||||
|     { | ||||
|         self::bootKernel(); | ||||
| @@ -55,52 +101,6 @@ final class ActivityControllerTest extends WebTestCase | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Provide a client unauthenticated and. | ||||
|      */ | ||||
|     public function getSecuredPagesUnauthenticated() | ||||
|     { | ||||
|         self::bootKernel(); | ||||
|         $person = $this->getPersonFromFixtures(); | ||||
|         $activities = $this->getActivitiesForPerson($person); | ||||
|  | ||||
|         return [ | ||||
|             [sprintf('fr/person/%d/activity/', $person->getId())], | ||||
|             [sprintf('fr/person/%d/activity/new', $person->getId())], | ||||
|             [sprintf('fr/person/%d/activity/%d/show', $person->getId(), $activities[0]->getId())], | ||||
|             [sprintf('fr/person/%d/activity/%d/edit', $person->getId(), $activities[0]->getId())], | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider getSecuredPagesUnauthenticated | ||||
|      */ | ||||
|     public function testAccessIsDeniedForUnauthenticated(mixed $url) | ||||
|     { | ||||
|         $client = $this->createClient(); | ||||
|  | ||||
|         $client->request('GET', $url); | ||||
|  | ||||
|         $this->assertEquals(302, $client->getResponse()->getStatusCode()); | ||||
|         $this->assertTrue( | ||||
|             $client->getResponse()->isRedirect('http://localhost/login'), | ||||
|             sprintf('the page "%s" does not redirect to http://localhost/login', $url) | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider getSecuredPagesAuthenticated | ||||
|      * | ||||
|      * @param type $client | ||||
|      * @param type $url | ||||
|      */ | ||||
|     public function testAccessIsDeniedForUnauthorized($client, $url) | ||||
|     { | ||||
|         $client->request('GET', $url); | ||||
|  | ||||
|         $this->assertEquals(403, $client->getResponse()->getStatusCode()); | ||||
|     } | ||||
|  | ||||
|     public function testCompleteScenario() | ||||
|     { | ||||
|         // Create a new client to browse the application | ||||
|   | ||||
| @@ -137,6 +137,64 @@ class ActivityACLAwareRepositoryTest extends KernelTestCase | ||||
|         self::assertIsArray($actual); | ||||
|     } | ||||
|  | ||||
|     public function provideDataFindByAccompanyingPeriod(): iterable | ||||
|     { | ||||
|         $this->setUp(); | ||||
|  | ||||
|         if (null === $period = $this->entityManager | ||||
|             ->createQueryBuilder() | ||||
|             ->select('a') | ||||
|             ->from(AccompanyingPeriod::class, 'a') | ||||
|             ->setMaxResults(1) | ||||
|             ->getQuery() | ||||
|             ->getSingleResult()) { | ||||
|             throw new \RuntimeException('no period found'); | ||||
|         } | ||||
|  | ||||
|         if ([] === $types = $this->entityManager | ||||
|             ->createQueryBuilder() | ||||
|             ->select('t') | ||||
|             ->from(ActivityType::class, 't') | ||||
|             ->setMaxResults(2) | ||||
|             ->getQuery() | ||||
|             ->getResult()) { | ||||
|             throw new \RuntimeException('no types'); | ||||
|         } | ||||
|  | ||||
|         if ([] === $jobs = $this->entityManager | ||||
|             ->createQueryBuilder() | ||||
|             ->select('j') | ||||
|             ->from(UserJob::class, 'j') | ||||
|             ->setMaxResults(2) | ||||
|             ->getQuery() | ||||
|             ->getResult() | ||||
|         ) { | ||||
|             $job = new UserJob(); | ||||
|             $job->setLabel(['fr' => 'test']); | ||||
|             $this->entityManager->persist($job); | ||||
|             $this->entityManager->flush(); | ||||
|         } | ||||
|  | ||||
|         if (null === $user = $this->entityManager | ||||
|             ->createQueryBuilder() | ||||
|             ->select('u') | ||||
|             ->from(User::class, 'u') | ||||
|             ->setMaxResults(1) | ||||
|             ->getQuery() | ||||
|             ->getSingleResult() | ||||
|         ) { | ||||
|             throw new \RuntimeException('no user found'); | ||||
|         } | ||||
|  | ||||
|         yield [$period, $user, ActivityVoter::SEE, 0, 10, ['date' => 'DESC'], []]; | ||||
|         yield [$period, $user, ActivityVoter::SEE, 0, 10, ['date' => 'DESC'], ['my_activities' => true]]; | ||||
|         yield [$period, $user, ActivityVoter::SEE, 0, 10, ['date' => 'DESC'], ['types' => $types]]; | ||||
|         yield [$period, $user, ActivityVoter::SEE, 0, 10, ['date' => 'DESC'], ['jobs' => $jobs]]; | ||||
|         yield [$period, $user, ActivityVoter::SEE, 0, 10, ['date' => 'DESC'], ['after' => new \DateTimeImmutable('1 year ago')]]; | ||||
|         yield [$period, $user, ActivityVoter::SEE, 0, 10, ['date' => 'DESC'], ['before' => new \DateTimeImmutable('1 year ago')]]; | ||||
|         yield [$period, $user, ActivityVoter::SEE, 0, 10, ['date' => 'DESC'], ['after' => new \DateTimeImmutable('1 year ago'), 'before' => new \DateTimeImmutable('1 month ago')]]; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider provideDataFindByPerson | ||||
|      */ | ||||
| @@ -291,62 +349,4 @@ class ActivityACLAwareRepositoryTest extends KernelTestCase | ||||
|         yield [$person, $user, $centers, $scopes, ActivityVoter::SEE, 0, 5, ['date' => 'DESC'], ['before' => new \DateTimeImmutable('1 year ago')]]; | ||||
|         yield [$person, $user, $centers, $scopes, ActivityVoter::SEE, 0, 5, ['date' => 'DESC'], ['after' => new \DateTimeImmutable('1 year ago'), 'before' => new \DateTimeImmutable('1 month ago')]]; | ||||
|     } | ||||
|  | ||||
|     public function provideDataFindByAccompanyingPeriod(): iterable | ||||
|     { | ||||
|         $this->setUp(); | ||||
|  | ||||
|         if (null === $period = $this->entityManager | ||||
|             ->createQueryBuilder() | ||||
|             ->select('a') | ||||
|             ->from(AccompanyingPeriod::class, 'a') | ||||
|             ->setMaxResults(1) | ||||
|             ->getQuery() | ||||
|             ->getSingleResult()) { | ||||
|             throw new \RuntimeException('no period found'); | ||||
|         } | ||||
|  | ||||
|         if ([] === $types = $this->entityManager | ||||
|             ->createQueryBuilder() | ||||
|             ->select('t') | ||||
|             ->from(ActivityType::class, 't') | ||||
|             ->setMaxResults(2) | ||||
|             ->getQuery() | ||||
|             ->getResult()) { | ||||
|             throw new \RuntimeException('no types'); | ||||
|         } | ||||
|  | ||||
|         if ([] === $jobs = $this->entityManager | ||||
|             ->createQueryBuilder() | ||||
|             ->select('j') | ||||
|             ->from(UserJob::class, 'j') | ||||
|             ->setMaxResults(2) | ||||
|             ->getQuery() | ||||
|             ->getResult() | ||||
|         ) { | ||||
|             $job = new UserJob(); | ||||
|             $job->setLabel(['fr' => 'test']); | ||||
|             $this->entityManager->persist($job); | ||||
|             $this->entityManager->flush(); | ||||
|         } | ||||
|  | ||||
|         if (null === $user = $this->entityManager | ||||
|             ->createQueryBuilder() | ||||
|             ->select('u') | ||||
|             ->from(User::class, 'u') | ||||
|             ->setMaxResults(1) | ||||
|             ->getQuery() | ||||
|             ->getSingleResult() | ||||
|         ) { | ||||
|             throw new \RuntimeException('no user found'); | ||||
|         } | ||||
|  | ||||
|         yield [$period, $user, ActivityVoter::SEE, 0, 10, ['date' => 'DESC'], []]; | ||||
|         yield [$period, $user, ActivityVoter::SEE, 0, 10, ['date' => 'DESC'], ['my_activities' => true]]; | ||||
|         yield [$period, $user, ActivityVoter::SEE, 0, 10, ['date' => 'DESC'], ['types' => $types]]; | ||||
|         yield [$period, $user, ActivityVoter::SEE, 0, 10, ['date' => 'DESC'], ['jobs' => $jobs]]; | ||||
|         yield [$period, $user, ActivityVoter::SEE, 0, 10, ['date' => 'DESC'], ['after' => new \DateTimeImmutable('1 year ago')]]; | ||||
|         yield [$period, $user, ActivityVoter::SEE, 0, 10, ['date' => 'DESC'], ['before' => new \DateTimeImmutable('1 year ago')]]; | ||||
|         yield [$period, $user, ActivityVoter::SEE, 0, 10, ['date' => 'DESC'], ['after' => new \DateTimeImmutable('1 year ago'), 'before' => new \DateTimeImmutable('1 month ago')]]; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -57,6 +57,46 @@ final class ActivityVoterTest extends KernelTestCase | ||||
|         $this->prophet = new \Prophecy\Prophet(); | ||||
|     } | ||||
|  | ||||
|     public function testNullUser() | ||||
|     { | ||||
|         $token = $this->prepareToken(); | ||||
|         $center = $this->prepareCenter(1, 'center'); | ||||
|         $person = $this->preparePerson($center); | ||||
|         $scope = $this->prepareScope(1, 'default'); | ||||
|         $activity = $this->prepareActivity($scope, $person); | ||||
|  | ||||
|         $this->assertEquals( | ||||
|             VoterInterface::ACCESS_DENIED, | ||||
|             $this->voter->vote($token, $activity, ['CHILL_ACTIVITY_SEE']), | ||||
|             'assert that a null user is not allowed to see' | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider dataProvider_testVoteAction | ||||
|      * | ||||
|      * @param type   $expectedResult | ||||
|      * @param string $attribute | ||||
|      * @param string $message | ||||
|      */ | ||||
|     public function testVoteAction( | ||||
|         $expectedResult, | ||||
|         User $user, | ||||
|         Scope $scope, | ||||
|         Center $center, | ||||
|         $attribute, | ||||
|         $message, | ||||
|     ) { | ||||
|         $token = $this->prepareToken($user); | ||||
|         $activity = $this->prepareActivity($scope, $this->preparePerson($center)); | ||||
|  | ||||
|         $this->assertEquals( | ||||
|             $expectedResult, | ||||
|             $this->voter->vote($token, $activity, [$attribute]), | ||||
|             $message | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     public function dataProvider_testVoteAction() | ||||
|     { | ||||
|         $centerA = $this->prepareCenter(1, 'center A'); | ||||
| @@ -110,46 +150,6 @@ final class ActivityVoterTest extends KernelTestCase | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|     public function testNullUser() | ||||
|     { | ||||
|         $token = $this->prepareToken(); | ||||
|         $center = $this->prepareCenter(1, 'center'); | ||||
|         $person = $this->preparePerson($center); | ||||
|         $scope = $this->prepareScope(1, 'default'); | ||||
|         $activity = $this->prepareActivity($scope, $person); | ||||
|  | ||||
|         $this->assertEquals( | ||||
|             VoterInterface::ACCESS_DENIED, | ||||
|             $this->voter->vote($token, $activity, ['CHILL_ACTIVITY_SEE']), | ||||
|             'assert that a null user is not allowed to see' | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider dataProvider_testVoteAction | ||||
|      * | ||||
|      * @param type   $expectedResult | ||||
|      * @param string $attribute | ||||
|      * @param string $message | ||||
|      */ | ||||
|     public function testVoteAction( | ||||
|         $expectedResult, | ||||
|         User $user, | ||||
|         Scope $scope, | ||||
|         Center $center, | ||||
|         $attribute, | ||||
|         $message, | ||||
|     ) { | ||||
|         $token = $this->prepareToken($user); | ||||
|         $activity = $this->prepareActivity($scope, $this->preparePerson($center)); | ||||
|  | ||||
|         $this->assertEquals( | ||||
|             $expectedResult, | ||||
|             $this->voter->vote($token, $activity, [$attribute]), | ||||
|             $message | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * prepare a token interface with correct rights. | ||||
|      * | ||||
|   | ||||
| @@ -30,6 +30,18 @@ final class AsideActivityControllerTest extends WebTestCase | ||||
|         self::ensureKernelShutdown(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider generateAsideActivityId | ||||
|      */ | ||||
|     public function testEditWithoutUsers(int $asideActivityId) | ||||
|     { | ||||
|         self::ensureKernelShutdown(); | ||||
|         $client = $this->getClientAuthenticated(); | ||||
|         $client->request('GET', "/fr/asideactivity/{$asideActivityId}/edit"); | ||||
|  | ||||
|         $this->assertEquals(200, $client->getResponse()->getStatusCode()); | ||||
|     } | ||||
|  | ||||
|     public static function generateAsideActivityId(): iterable | ||||
|     { | ||||
|         self::bootKernel(); | ||||
| @@ -58,18 +70,6 @@ final class AsideActivityControllerTest extends WebTestCase | ||||
|         self::ensureKernelShutdown(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider generateAsideActivityId | ||||
|      */ | ||||
|     public function testEditWithoutUsers(int $asideActivityId) | ||||
|     { | ||||
|         self::ensureKernelShutdown(); | ||||
|         $client = $this->getClientAuthenticated(); | ||||
|         $client->request('GET', "/fr/asideactivity/{$asideActivityId}/edit"); | ||||
|  | ||||
|         $this->assertEquals(200, $client->getResponse()->getStatusCode()); | ||||
|     } | ||||
|  | ||||
|     public function testIndexWithoutUsers() | ||||
|     { | ||||
|         self::ensureKernelShutdown(); | ||||
|   | ||||
| @@ -42,6 +42,32 @@ final class CalendarControllerTest extends WebTestCase | ||||
|         self::ensureKernelShutdown(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider provideAccompanyingPeriod | ||||
|      */ | ||||
|     public function testList(int $accompanyingPeriodId) | ||||
|     { | ||||
|         $this->client->request( | ||||
|             Request::METHOD_GET, | ||||
|             sprintf('/fr/calendar/calendar/by-period/%d', $accompanyingPeriodId) | ||||
|         ); | ||||
|  | ||||
|         $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider provideAccompanyingPeriod | ||||
|      */ | ||||
|     public function testNew(int $accompanyingPeriodId) | ||||
|     { | ||||
|         $this->client->request( | ||||
|             Request::METHOD_GET, | ||||
|             sprintf('/fr/calendar/calendar/new?accompanying_period_id=%d', $accompanyingPeriodId) | ||||
|         ); | ||||
|  | ||||
|         $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); | ||||
|     } | ||||
|  | ||||
|     public static function provideAccompanyingPeriod(): iterable | ||||
|     { | ||||
|         self::bootKernel(); | ||||
| @@ -82,30 +108,4 @@ final class CalendarControllerTest extends WebTestCase | ||||
|  | ||||
|         self::ensureKernelShutdown(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider provideAccompanyingPeriod | ||||
|      */ | ||||
|     public function testList(int $accompanyingPeriodId) | ||||
|     { | ||||
|         $this->client->request( | ||||
|             Request::METHOD_GET, | ||||
|             sprintf('/fr/calendar/calendar/by-period/%d', $accompanyingPeriodId) | ||||
|         ); | ||||
|  | ||||
|         $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider provideAccompanyingPeriod | ||||
|      */ | ||||
|     public function testNew(int $accompanyingPeriodId) | ||||
|     { | ||||
|         $this->client->request( | ||||
|             Request::METHOD_GET, | ||||
|             sprintf('/fr/calendar/calendar/new?accompanying_period_id=%d', $accompanyingPeriodId) | ||||
|         ); | ||||
|  | ||||
|         $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -45,20 +45,6 @@ class MSUserAbsenceReaderTest extends TestCase | ||||
|         self::assertEquals($expected, $absenceReader->isUserAbsent($user), $message); | ||||
|     } | ||||
|  | ||||
|     public function testIsUserAbsentWithoutRemoteId(): void | ||||
|     { | ||||
|         $user = new User(); | ||||
|         $client = new MockHttpClient(); | ||||
|  | ||||
|         $mapUser = $this->prophesize(MapCalendarToUser::class); | ||||
|         $mapUser->getUserId($user)->willReturn(null); | ||||
|         $clock = new MockClock(new \DateTimeImmutable('2023-07-07T12:00:00')); | ||||
|  | ||||
|         $absenceReader = new MSUserAbsenceReader($client, $mapUser->reveal(), $clock); | ||||
|  | ||||
|         self::assertNull($absenceReader->isUserAbsent($user), 'when no user found, absence should be null'); | ||||
|     } | ||||
|  | ||||
|     public static function provideDataTestUserAbsence(): iterable | ||||
|     { | ||||
|         // contains data that was retrieved from microsoft graph api on 2023-07-06 | ||||
| @@ -173,4 +159,18 @@ class MSUserAbsenceReaderTest extends TestCase | ||||
|             'User is absent: absence is always enabled', | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|     public function testIsUserAbsentWithoutRemoteId(): void | ||||
|     { | ||||
|         $user = new User(); | ||||
|         $client = new MockHttpClient(); | ||||
|  | ||||
|         $mapUser = $this->prophesize(MapCalendarToUser::class); | ||||
|         $mapUser->getUserId($user)->willReturn(null); | ||||
|         $clock = new MockClock(new \DateTimeImmutable('2023-07-07T12:00:00')); | ||||
|  | ||||
|         $absenceReader = new MSUserAbsenceReader($client, $mapUser->reveal(), $clock); | ||||
|  | ||||
|         self::assertNull($absenceReader->isUserAbsent($user), 'when no user found, absence should be null'); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -28,6 +28,24 @@ use PHPUnit\Framework\TestCase; | ||||
|  */ | ||||
| final class DefaultRangeGeneratorTest extends TestCase | ||||
| { | ||||
|     /** | ||||
|      * @dataProvider generateData | ||||
|      */ | ||||
|     public function testGenerateRange(\DateTimeImmutable $date, ?\DateTimeImmutable $startDate, ?\DateTimeImmutable $endDate) | ||||
|     { | ||||
|         $generator = new DefaultRangeGenerator(); | ||||
|  | ||||
|         ['startDate' => $actualStartDate, 'endDate' => $actualEndDate] = $generator->generateRange($date); | ||||
|  | ||||
|         if (null === $startDate) { | ||||
|             $this->assertNull($actualStartDate); | ||||
|             $this->assertNull($actualEndDate); | ||||
|         } else { | ||||
|             $this->assertEquals($startDate->format(\DateTimeImmutable::ATOM), $actualStartDate->format(\DateTimeImmutable::ATOM)); | ||||
|             $this->assertEquals($endDate->format(\DateTimeImmutable::ATOM), $actualEndDate->format(\DateTimeImmutable::ATOM)); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * * Lundi => Envoi des rdv du mardi et mercredi. | ||||
|      * * Mardi => Envoi des rdv du jeudi. | ||||
| @@ -79,22 +97,4 @@ final class DefaultRangeGeneratorTest extends TestCase | ||||
|             null, | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider generateData | ||||
|      */ | ||||
|     public function testGenerateRange(\DateTimeImmutable $date, ?\DateTimeImmutable $startDate, ?\DateTimeImmutable $endDate) | ||||
|     { | ||||
|         $generator = new DefaultRangeGenerator(); | ||||
|  | ||||
|         ['startDate' => $actualStartDate, 'endDate' => $actualEndDate] = $generator->generateRange($date); | ||||
|  | ||||
|         if (null === $startDate) { | ||||
|             $this->assertNull($actualStartDate); | ||||
|             $this->assertNull($actualEndDate); | ||||
|         } else { | ||||
|             $this->assertEquals($startDate->format(\DateTimeImmutable::ATOM), $actualStartDate->format(\DateTimeImmutable::ATOM)); | ||||
|             $this->assertEquals($endDate->format(\DateTimeImmutable::ATOM), $actualEndDate->format(\DateTimeImmutable::ATOM)); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -49,80 +49,6 @@ final class CustomFieldsChoiceTest extends KernelTestCase | ||||
|         parent::tearDown(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * provide empty data in different possible representations. | ||||
|      * Those data are supposed to be deserialized. | ||||
|      * | ||||
|      * @return array | ||||
|      */ | ||||
|     public static function emptyDataProvider() | ||||
|     { | ||||
|         return [ | ||||
|             // 0 | ||||
|             [ | ||||
|                 // signle | ||||
|                 '', | ||||
|             ], | ||||
|             // 1 | ||||
|             [ | ||||
|                 // single | ||||
|                 null, | ||||
|             ], | ||||
|             // 2 | ||||
|             [ | ||||
|                 // signle with allow other | ||||
|                 ['_other' => 'something', '_choices' => ''], | ||||
|             ], | ||||
|             // 3 | ||||
|             [ | ||||
|                 // multiple | ||||
|                 [], | ||||
|             ], | ||||
|             // 4 | ||||
|             [ | ||||
|                 // multiple with allow other | ||||
|                 ['_other' => 'something', '_choices' => []], | ||||
|             ], | ||||
|             // 5 | ||||
|             [ | ||||
|                 // multiple with allow other | ||||
|                 ['_other' => '', '_choices' => []], | ||||
|             ], | ||||
|             // 6 | ||||
|             [ | ||||
|                 // empty | ||||
|                 ['_other' => null, '_choices' => null], | ||||
|             ], | ||||
|             // 7 | ||||
|             [ | ||||
|                 // empty | ||||
|                 [null], | ||||
|             ], | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|     public static function serializedRepresentationDataProvider() | ||||
|     { | ||||
|         return [ | ||||
|             [ | ||||
|                 // multiple => false, allow_other => false | ||||
|                 'my-value', | ||||
|             ], | ||||
|             [ | ||||
|                 // multiple => true, allow_ther => false | ||||
|                 ['my-value'], | ||||
|             ], | ||||
|             [ | ||||
|                 // multiple => false, allow_other => true, current value not in other | ||||
|                 ['_other' => '', '_choices' => 'my-value'], | ||||
|             ], | ||||
|             [ | ||||
|                 // multiple => true, allow_other => true, current value not in other | ||||
|                 ['_other' => '', '_choices' => ['my-value']], | ||||
|             ], | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Test if the representation of the data is deserialized to an array text | ||||
|      * with an "allow_other" field. | ||||
| @@ -412,6 +338,58 @@ final class CustomFieldsChoiceTest extends KernelTestCase | ||||
|         $this->assertTrue($isEmpty); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * provide empty data in different possible representations. | ||||
|      * Those data are supposed to be deserialized. | ||||
|      * | ||||
|      * @return array | ||||
|      */ | ||||
|     public static function emptyDataProvider() | ||||
|     { | ||||
|         return [ | ||||
|             // 0 | ||||
|             [ | ||||
|                 // signle | ||||
|                 '', | ||||
|             ], | ||||
|             // 1 | ||||
|             [ | ||||
|                 // single | ||||
|                 null, | ||||
|             ], | ||||
|             // 2 | ||||
|             [ | ||||
|                 // signle with allow other | ||||
|                 ['_other' => 'something', '_choices' => ''], | ||||
|             ], | ||||
|             // 3 | ||||
|             [ | ||||
|                 // multiple | ||||
|                 [], | ||||
|             ], | ||||
|             // 4 | ||||
|             [ | ||||
|                 // multiple with allow other | ||||
|                 ['_other' => 'something', '_choices' => []], | ||||
|             ], | ||||
|             // 5 | ||||
|             [ | ||||
|                 // multiple with allow other | ||||
|                 ['_other' => '', '_choices' => []], | ||||
|             ], | ||||
|             // 6 | ||||
|             [ | ||||
|                 // empty | ||||
|                 ['_other' => null, '_choices' => null], | ||||
|             ], | ||||
|             // 7 | ||||
|             [ | ||||
|                 // empty | ||||
|                 [null], | ||||
|             ], | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|     // /////////////////////////////////////// | ||||
|     // | ||||
|     // test function isEmptyValue | ||||
| @@ -435,6 +413,28 @@ final class CustomFieldsChoiceTest extends KernelTestCase | ||||
|         $this->assertFalse($isEmpty); | ||||
|     } | ||||
|  | ||||
|     public static function serializedRepresentationDataProvider() | ||||
|     { | ||||
|         return [ | ||||
|             [ | ||||
|                 // multiple => false, allow_other => false | ||||
|                 'my-value', | ||||
|             ], | ||||
|             [ | ||||
|                 // multiple => true, allow_ther => false | ||||
|                 ['my-value'], | ||||
|             ], | ||||
|             [ | ||||
|                 // multiple => false, allow_other => true, current value not in other | ||||
|                 ['_other' => '', '_choices' => 'my-value'], | ||||
|             ], | ||||
|             [ | ||||
|                 // multiple => true, allow_other => true, current value not in other | ||||
|                 ['_other' => '', '_choices' => ['my-value']], | ||||
|             ], | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param array $options | ||||
|      * | ||||
|   | ||||
| @@ -58,6 +58,7 @@ | ||||
|  | ||||
| <script> | ||||
| import { buildLink } from "ChillDocGeneratorAssets/lib/document-generator"; | ||||
| import { localizeString } from "ChillMainAssets/lib/localizationHelper/localizationHelper"; | ||||
|  | ||||
| export default { | ||||
|     name: "PickTemplate", | ||||
| @@ -113,6 +114,9 @@ export default { | ||||
|         }, | ||||
|     }, | ||||
|     methods: { | ||||
|         localizeString(str) { | ||||
|             return localizeString(str); | ||||
|         }, | ||||
|         clickGenerate(event, link) { | ||||
|             if (!this.preventDefaultMoveToGenerate) { | ||||
|                 window.location.assign(link); | ||||
|   | ||||
| @@ -1,7 +1,5 @@ | ||||
| {{ 'docgen.data_dump_email.Dear'|trans }} | ||||
|  | ||||
| {{ 'docgen.data_dump_email.data_dump_ready_and_link'|trans }} | ||||
| {{ 'docgen.data_dump_email.data_dump_ready_and_attached'|trans }} | ||||
|  | ||||
| {{ link }} | ||||
|  | ||||
| {{ 'docgen.data_dump_email.link_valid_until'|trans({validity: validity}) }} | ||||
| {{ 'docgen.data_dump_email.filename'|trans({filename: filename}) }} | ||||
|   | ||||
| @@ -11,13 +11,13 @@ declare(strict_types=1); | ||||
|  | ||||
| namespace Chill\DocGeneratorBundle\Service\Messenger; | ||||
|  | ||||
| use Chill\DocGeneratorBundle\Repository\DocGeneratorTemplateRepository; | ||||
| use Chill\DocGeneratorBundle\Service\Generator\Generator; | ||||
| use Chill\DocGeneratorBundle\Repository\DocGeneratorTemplateRepositoryInterface; | ||||
| use Chill\DocGeneratorBundle\Service\Generator\GeneratorException; | ||||
| use Chill\DocStoreBundle\AsyncUpload\TempUrlGeneratorInterface; | ||||
| use Chill\DocGeneratorBundle\Service\Generator\GeneratorInterface; | ||||
| use Chill\DocStoreBundle\Entity\StoredObject; | ||||
| use Chill\DocStoreBundle\Exception\StoredObjectManagerException; | ||||
| use Chill\DocStoreBundle\Repository\StoredObjectRepository; | ||||
| use Chill\DocStoreBundle\Repository\StoredObjectRepositoryInterface; | ||||
| use Chill\DocStoreBundle\Service\StoredObjectManagerInterface; | ||||
| use Chill\MainBundle\Repository\UserRepositoryInterface; | ||||
| use Doctrine\ORM\EntityManagerInterface; | ||||
| use Psr\Log\LoggerInterface; | ||||
| @@ -37,15 +37,15 @@ class RequestGenerationHandler implements MessageHandlerInterface | ||||
|     private const LOG_PREFIX = '[docgen message handler] '; | ||||
|  | ||||
|     public function __construct( | ||||
|         private readonly DocGeneratorTemplateRepository $docGeneratorTemplateRepository, | ||||
|         private readonly DocGeneratorTemplateRepositoryInterface $docGeneratorTemplateRepository, | ||||
|         private readonly EntityManagerInterface $entityManager, | ||||
|         private readonly Generator $generator, | ||||
|         private readonly GeneratorInterface $generator, | ||||
|         private readonly LoggerInterface $logger, | ||||
|         private readonly StoredObjectRepository $storedObjectRepository, | ||||
|         private readonly StoredObjectRepositoryInterface $storedObjectRepository, | ||||
|         private readonly UserRepositoryInterface $userRepository, | ||||
|         private readonly MailerInterface $mailer, | ||||
|         private readonly TempUrlGeneratorInterface $tempUrlGenerator, | ||||
|         private readonly TranslatorInterface $translator, | ||||
|         private readonly StoredObjectManagerInterface $storedObjectManager, | ||||
|     ) {} | ||||
|  | ||||
|     public function __invoke(RequestGenerationMessage $message) | ||||
| @@ -90,7 +90,7 @@ class RequestGenerationHandler implements MessageHandlerInterface | ||||
|  | ||||
|                 $this->sendDataDump($destinationStoredObject, $message); | ||||
|             } else { | ||||
|                 $destinationStoredObject = $this->generator->generateDocFromTemplate( | ||||
|                 $this->generator->generateDocFromTemplate( | ||||
|                     $template, | ||||
|                     $message->getEntityId(), | ||||
|                     $message->getContextGenerationData(), | ||||
| @@ -122,19 +122,20 @@ class RequestGenerationHandler implements MessageHandlerInterface | ||||
|  | ||||
|     private function sendDataDump(StoredObject $destinationStoredObject, RequestGenerationMessage $message): void | ||||
|     { | ||||
|         $url = $this->tempUrlGenerator->generate('GET', $destinationStoredObject->getFilename(), 3600); | ||||
|         $parts = []; | ||||
|         parse_str(parse_url($url->url)['query'], $parts); | ||||
|         $validity = \DateTimeImmutable::createFromFormat('U', $parts['temp_url_expires']); | ||||
|         // Get the content of the document | ||||
|         $content = $this->storedObjectManager->read($destinationStoredObject); | ||||
|         $filename = $destinationStoredObject->getFilename(); | ||||
|         $contentType = $destinationStoredObject->getType(); | ||||
|  | ||||
|         // Create the email with the document as an attachment | ||||
|         $email = (new TemplatedEmail()) | ||||
|             ->to($message->getSendResultToEmail()) | ||||
|             ->textTemplate('@ChillDocGenerator/Email/send_data_dump_to_admin.txt.twig') | ||||
|             ->context([ | ||||
|                 'link' => $url->url, | ||||
|                 'validity' => $validity, | ||||
|                 'filename' => $filename, | ||||
|             ]) | ||||
|             ->subject($this->translator->trans('docgen.data_dump_email.subject')); | ||||
|             ->subject($this->translator->trans('docgen.data_dump_email.subject')) | ||||
|             ->attach($content, $filename, $contentType); | ||||
|  | ||||
|         $this->mailer->send($email); | ||||
|     } | ||||
|   | ||||
| @@ -0,0 +1,132 @@ | ||||
| <?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 Chill\DocGeneratorBundle\Tests\Service\Messenger; | ||||
|  | ||||
| use Chill\DocGeneratorBundle\Entity\DocGeneratorTemplate; | ||||
| use Chill\DocGeneratorBundle\Repository\DocGeneratorTemplateRepositoryInterface; | ||||
| use Chill\DocGeneratorBundle\Service\Generator\GeneratorInterface; | ||||
| use Chill\DocGeneratorBundle\Service\Messenger\RequestGenerationHandler; | ||||
| use Chill\DocGeneratorBundle\Service\Messenger\RequestGenerationMessage; | ||||
| use Chill\DocStoreBundle\Entity\StoredObject; | ||||
| use Chill\DocStoreBundle\Repository\StoredObjectRepositoryInterface; | ||||
| use Chill\DocStoreBundle\Service\StoredObjectManagerInterface; | ||||
| use Chill\MainBundle\Entity\User; | ||||
| use Chill\MainBundle\Repository\UserRepositoryInterface; | ||||
| use Doctrine\ORM\EntityManagerInterface; | ||||
| use Doctrine\ORM\Query; | ||||
| use PHPUnit\Framework\TestCase; | ||||
| use Prophecy\Argument; | ||||
| use Prophecy\PhpUnit\ProphecyTrait; | ||||
| use Psr\Log\NullLogger; | ||||
| use Symfony\Component\Mailer\MailerInterface; | ||||
| use Symfony\Contracts\Translation\TranslatorInterface; | ||||
|  | ||||
| /** | ||||
|  * @internal | ||||
|  * | ||||
|  * @coversNothing | ||||
|  */ | ||||
| class RequestGenerationHandlerTest extends TestCase | ||||
| { | ||||
|     use ProphecyTrait; | ||||
|  | ||||
|     public function testGenerationHappyScenario(): void | ||||
|     { | ||||
|         // Create entities | ||||
|         $template = new DocGeneratorTemplate(); | ||||
|         $this->setPrivateProperty($template, 'id', 1); | ||||
|  | ||||
|         $storedObject = new StoredObject(); | ||||
|         $this->setPrivateProperty($storedObject, 'id', 2); | ||||
|  | ||||
|         $creator = new User(); | ||||
|         $creator->setEmail('test@example.com'); | ||||
|         $this->setPrivateProperty($creator, 'id', 3); | ||||
|  | ||||
|         $docGeneratorTemplateRepository = $this->prophesize(DocGeneratorTemplateRepositoryInterface::class); | ||||
|         $docGeneratorTemplateRepository->find(1)->willReturn($template); | ||||
|  | ||||
|         $storedObjectRepository = $this->prophesize(StoredObjectRepositoryInterface::class); | ||||
|         $storedObjectRepository->find(2)->willReturn($storedObject); | ||||
|  | ||||
|         $userRepository = $this->prophesize(UserRepositoryInterface::class); | ||||
|         $userRepository->find(3)->willReturn($creator); | ||||
|  | ||||
|         // Create a mock for the Query object | ||||
|         $query = $this->prophesize(Query::class); | ||||
|         $query->setParameter('id', 2)->willReturn($query->reveal()); | ||||
|         $query->execute()->shouldBeCalled(); | ||||
|  | ||||
|         // Create a mock for the EntityManager | ||||
|         $entityManager = $this->prophesize(EntityManagerInterface::class); | ||||
|         $entityManager->createQuery(Argument::containingString('UPDATE'))->willReturn($query->reveal()); | ||||
|         $entityManager->flush()->shouldBeCalled(); | ||||
|  | ||||
|         $generator = $this->prophesize(GeneratorInterface::class); | ||||
|         $generator->generateDocFromTemplate( | ||||
|             $template, | ||||
|             123, // entityId | ||||
|             ['key' => 'value'], // contextGenerationData | ||||
|             $storedObject, | ||||
|             $creator | ||||
|         ) | ||||
|             ->willReturn($storedObject)->shouldBeCalled(); | ||||
|  | ||||
|         $logger = new NullLogger(); | ||||
|  | ||||
|         $mailer = $this->prophesize(MailerInterface::class); | ||||
|  | ||||
|         $translator = $this->prophesize(TranslatorInterface::class); | ||||
|  | ||||
|         $storedObjectManager = $this->prophesize(StoredObjectManagerInterface::class); | ||||
|  | ||||
|         // Create handler | ||||
|         $handler = new RequestGenerationHandler( | ||||
|             $docGeneratorTemplateRepository->reveal(), | ||||
|             $entityManager->reveal(), | ||||
|             $generator->reveal(), | ||||
|             $logger, | ||||
|             $storedObjectRepository->reveal(), | ||||
|             $userRepository->reveal(), | ||||
|             $mailer->reveal(), | ||||
|             $translator->reveal(), | ||||
|             $storedObjectManager->reveal() | ||||
|         ); | ||||
|  | ||||
|         // Create message | ||||
|         $message = new RequestGenerationMessage( | ||||
|             $creator, | ||||
|             $template, | ||||
|             123, // entityId | ||||
|             $storedObject, | ||||
|             ['key' => 'value'], // contextGenerationData | ||||
|             false, // isTest | ||||
|             null, // sendResultToEmail | ||||
|             false // dumpOnly | ||||
|         ); | ||||
|  | ||||
|         // Invoke handler | ||||
|         $handler->__invoke($message); | ||||
|  | ||||
|         // Assertions | ||||
|         // The assertions are handled by the shouldBeCalled() expectations on the mocks | ||||
|         $this->assertTrue(true); // Just to have an assertion in the test | ||||
|     } | ||||
|  | ||||
|     private function setPrivateProperty(object $object, string $propertyName, $value): void | ||||
|     { | ||||
|         $reflection = new \ReflectionClass($object); | ||||
|         $property = $reflection->getProperty($propertyName); | ||||
|         $property->setAccessible(true); | ||||
|         $property->setValue($object, $value); | ||||
|     } | ||||
| } | ||||
| @@ -31,6 +31,36 @@ final class DocGenEncoderTest extends TestCase | ||||
|         $this->encoder = new DocGenEncoder(); | ||||
|     } | ||||
|  | ||||
|     public function testEmbeddedLoopsThrowsException() | ||||
|     { | ||||
|         $this->expectException(UnexpectedValueException::class); | ||||
|  | ||||
|         $data = [ | ||||
|             'data' => [ | ||||
|                 ['item' => 'one'], | ||||
|                 [ | ||||
|                     'embedded' => [ | ||||
|                         [ | ||||
|                             ['subitem' => 'two'], | ||||
|                             ['subitem' => 'three'], | ||||
|                         ], | ||||
|                     ], | ||||
|                 ], | ||||
|             ], | ||||
|         ]; | ||||
|  | ||||
|         $this->encoder->encode($data, 'docgen'); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider generateEncodeData | ||||
|      */ | ||||
|     public function testEncode(mixed $expected, mixed $data, string $msg) | ||||
|     { | ||||
|         $generated = $this->encoder->encode($data, 'docgen'); | ||||
|         $this->assertEquals($expected, $generated, $msg); | ||||
|     } | ||||
|  | ||||
|     public static function generateEncodeData() | ||||
|     { | ||||
|         yield [['tests' => 'ok'], ['tests' => 'ok'], 'A simple test with a simple array']; | ||||
| @@ -93,34 +123,4 @@ final class DocGenEncoderTest extends TestCase | ||||
|             'a longer list, with near real data inside and embedded associative arrays', | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|     public function testEmbeddedLoopsThrowsException() | ||||
|     { | ||||
|         $this->expectException(UnexpectedValueException::class); | ||||
|  | ||||
|         $data = [ | ||||
|             'data' => [ | ||||
|                 ['item' => 'one'], | ||||
|                 [ | ||||
|                     'embedded' => [ | ||||
|                         [ | ||||
|                             ['subitem' => 'two'], | ||||
|                             ['subitem' => 'three'], | ||||
|                         ], | ||||
|                     ], | ||||
|                 ], | ||||
|             ], | ||||
|         ]; | ||||
|  | ||||
|         $this->encoder->encode($data, 'docgen'); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider generateEncodeData | ||||
|      */ | ||||
|     public function testEncode(mixed $expected, mixed $data, string $msg) | ||||
|     { | ||||
|         $generated = $this->encoder->encode($data, 'docgen'); | ||||
|         $this->assertEquals($expected, $generated, $msg); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,4 +1,2 @@ | ||||
| docgen: | ||||
|     data_dump_email: | ||||
|         link_valid_until: >- | ||||
|             Ce lien est valide jusqu'au {validity, date, full}, {validity, time, medium} | ||||
|     # No ICU messages needed for data_dump_email anymore | ||||
|   | ||||
| @@ -34,8 +34,10 @@ docgen: | ||||
|     data_dump_email: | ||||
|         subject: Contenu des données de génération de document disponible | ||||
|         Dear: Cher | ||||
|         data_dump_ready_and_link: >- | ||||
|             Le contenu des données est disponible. Vous pouvez le télécharger à l'aide du lien suivant: | ||||
|         data_dump_ready_and_attached: >- | ||||
|             Le contenu des données est disponible. Vous le trouverez en pièce jointe à cet email. | ||||
|         filename: >- | ||||
|             Nom du fichier: %filename% | ||||
|  | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -85,6 +85,69 @@ class TempUrlLocalStorageGeneratorTest extends TestCase | ||||
|         self::assertEquals($expected, $urlGenerator->validateSignature($signature, $method, $objectName, $expiration), $message); | ||||
|     } | ||||
|  | ||||
|     public static function generateValidateSignatureData(): iterable | ||||
|     { | ||||
|         yield [ | ||||
|             TempUrlLocalStorageGeneratorTest::expectedSignature('GET', $object_name = 'testABC', $expiration = 1734307200 + 180), | ||||
|             'GET', | ||||
|             $object_name, | ||||
|             $expiration, | ||||
|             \DateTimeImmutable::createFromFormat('U', (string) ($expiration - 10)), | ||||
|             true, | ||||
|             'Valid signature, not expired', | ||||
|         ]; | ||||
|  | ||||
|         yield [ | ||||
|             TempUrlLocalStorageGeneratorTest::expectedSignature('HEAD', $object_name = 'testABC', $expiration = 1734307200 + 180), | ||||
|             'HEAD', | ||||
|             $object_name, | ||||
|             $expiration, | ||||
|             \DateTimeImmutable::createFromFormat('U', (string) ($expiration - 10)), | ||||
|             true, | ||||
|             'Valid signature, not expired', | ||||
|         ]; | ||||
|  | ||||
|         yield [ | ||||
|             TempUrlLocalStorageGeneratorTest::expectedSignature('GET', $object_name = 'testABC', $expiration = 1734307200 + 180).'A', | ||||
|             'GET', | ||||
|             $object_name, | ||||
|             $expiration, | ||||
|             \DateTimeImmutable::createFromFormat('U', (string) ($expiration - 10)), | ||||
|             false, | ||||
|             'Invalid signature', | ||||
|         ]; | ||||
|  | ||||
|         yield [ | ||||
|             TempUrlLocalStorageGeneratorTest::expectedSignature('GET', $object_name = 'testABC', $expiration = 1734307200 + 180), | ||||
|             'GET', | ||||
|             $object_name, | ||||
|             $expiration, | ||||
|             \DateTimeImmutable::createFromFormat('U', (string) ($expiration + 1)), | ||||
|             false, | ||||
|             'Signature expired', | ||||
|         ]; | ||||
|  | ||||
|         yield [ | ||||
|             TempUrlLocalStorageGeneratorTest::expectedSignature('GET', $object_name = 'testABC', $expiration = 1734307200 + 180), | ||||
|             'GET', | ||||
|             $object_name.'____', | ||||
|             $expiration, | ||||
|             \DateTimeImmutable::createFromFormat('U', (string) ($expiration - 10)), | ||||
|             false, | ||||
|             'Invalid object name', | ||||
|         ]; | ||||
|  | ||||
|         yield [ | ||||
|             TempUrlLocalStorageGeneratorTest::expectedSignature('POST', $object_name = 'testABC', $expiration = 1734307200 + 180), | ||||
|             'POST', | ||||
|             $object_name, | ||||
|             $expiration, | ||||
|             \DateTimeImmutable::createFromFormat('U', (string) ($expiration - 10)), | ||||
|             false, | ||||
|             'Wrong method', | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider generateValidateSignaturePostData | ||||
|      */ | ||||
| @@ -164,69 +227,6 @@ class TempUrlLocalStorageGeneratorTest extends TestCase | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|     public static function generateValidateSignatureData(): iterable | ||||
|     { | ||||
|         yield [ | ||||
|             TempUrlLocalStorageGeneratorTest::expectedSignature('GET', $object_name = 'testABC', $expiration = 1734307200 + 180), | ||||
|             'GET', | ||||
|             $object_name, | ||||
|             $expiration, | ||||
|             \DateTimeImmutable::createFromFormat('U', (string) ($expiration - 10)), | ||||
|             true, | ||||
|             'Valid signature, not expired', | ||||
|         ]; | ||||
|  | ||||
|         yield [ | ||||
|             TempUrlLocalStorageGeneratorTest::expectedSignature('HEAD', $object_name = 'testABC', $expiration = 1734307200 + 180), | ||||
|             'HEAD', | ||||
|             $object_name, | ||||
|             $expiration, | ||||
|             \DateTimeImmutable::createFromFormat('U', (string) ($expiration - 10)), | ||||
|             true, | ||||
|             'Valid signature, not expired', | ||||
|         ]; | ||||
|  | ||||
|         yield [ | ||||
|             TempUrlLocalStorageGeneratorTest::expectedSignature('GET', $object_name = 'testABC', $expiration = 1734307200 + 180).'A', | ||||
|             'GET', | ||||
|             $object_name, | ||||
|             $expiration, | ||||
|             \DateTimeImmutable::createFromFormat('U', (string) ($expiration - 10)), | ||||
|             false, | ||||
|             'Invalid signature', | ||||
|         ]; | ||||
|  | ||||
|         yield [ | ||||
|             TempUrlLocalStorageGeneratorTest::expectedSignature('GET', $object_name = 'testABC', $expiration = 1734307200 + 180), | ||||
|             'GET', | ||||
|             $object_name, | ||||
|             $expiration, | ||||
|             \DateTimeImmutable::createFromFormat('U', (string) ($expiration + 1)), | ||||
|             false, | ||||
|             'Signature expired', | ||||
|         ]; | ||||
|  | ||||
|         yield [ | ||||
|             TempUrlLocalStorageGeneratorTest::expectedSignature('GET', $object_name = 'testABC', $expiration = 1734307200 + 180), | ||||
|             'GET', | ||||
|             $object_name.'____', | ||||
|             $expiration, | ||||
|             \DateTimeImmutable::createFromFormat('U', (string) ($expiration - 10)), | ||||
|             false, | ||||
|             'Invalid object name', | ||||
|         ]; | ||||
|  | ||||
|         yield [ | ||||
|             TempUrlLocalStorageGeneratorTest::expectedSignature('POST', $object_name = 'testABC', $expiration = 1734307200 + 180), | ||||
|             'POST', | ||||
|             $object_name, | ||||
|             $expiration, | ||||
|             \DateTimeImmutable::createFromFormat('U', (string) ($expiration - 10)), | ||||
|             false, | ||||
|             'Wrong method', | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|     private function buildGenerator(?UrlGeneratorInterface $urlGenerator = null, ?ClockInterface $clock = null): TempUrlLocalStorageGenerator | ||||
|     { | ||||
|         return new TempUrlLocalStorageGenerator( | ||||
|   | ||||
| @@ -31,6 +31,20 @@ use Symfony\Contracts\HttpClient\HttpClientInterface; | ||||
|  */ | ||||
| final class StoredObjectManagerTest extends TestCase | ||||
| { | ||||
|     /** | ||||
|      * @dataProvider getDataProviderForRead | ||||
|      */ | ||||
|     public function testRead(StoredObject $storedObject, string $encodedContent, string $clearContent, ?string $exceptionClass = null) | ||||
|     { | ||||
|         if (null !== $exceptionClass) { | ||||
|             $this->expectException($exceptionClass); | ||||
|         } | ||||
|  | ||||
|         $storedObjectManager = $this->getSubject($storedObject, $encodedContent); | ||||
|  | ||||
|         self::assertEquals($clearContent, $storedObjectManager->read($storedObject)); | ||||
|     } | ||||
|  | ||||
|     public static function getDataProviderForRead(): \Generator | ||||
|     { | ||||
|         /* HAPPY SCENARIO */ | ||||
| @@ -96,6 +110,40 @@ final class StoredObjectManagerTest extends TestCase | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider getDataProviderForWrite | ||||
|      */ | ||||
|     public function testWrite(StoredObject $storedObject, string $encodedContent, string $clearContent, ?string $exceptionClass = null, ?int $errorCode = null) | ||||
|     { | ||||
|         if (null !== $exceptionClass) { | ||||
|             $this->expectException($exceptionClass); | ||||
|         } | ||||
|  | ||||
|         $previousVersion = $storedObject->getCurrentVersion(); | ||||
|         $previousFilename = $previousVersion->getFilename(); | ||||
|  | ||||
|         $client = new MockHttpClient(function ($method, $url, $options) use ($encodedContent, $previousFilename, $errorCode) { | ||||
|             self::assertEquals('PUT', $method); | ||||
|             self::assertStringStartsWith('https://example.com/', $url); | ||||
|             self::assertStringNotContainsString($previousFilename, $url, 'test that the PUT operation is not performed on the same file'); | ||||
|             self::assertArrayHasKey('body', $options); | ||||
|             self::assertEquals($encodedContent, $options['body']); | ||||
|  | ||||
|             if (-1 === $errorCode) { | ||||
|                 throw new TransportException(); | ||||
|             } | ||||
|  | ||||
|             return new MockResponse('', ['http_code' => $errorCode ?? 201]); | ||||
|         }); | ||||
|  | ||||
|         $storedObjectManager = new StoredObjectManager($client, $this->getTempUrlGenerator($storedObject)); | ||||
|  | ||||
|         $newVersion = $storedObjectManager->write($storedObject, $clearContent); | ||||
|  | ||||
|         self::assertNotSame($previousVersion, $newVersion); | ||||
|         self::assertSame($storedObject->getCurrentVersion(), $newVersion); | ||||
|     } | ||||
|  | ||||
|     public static function getDataProviderForWrite(): \Generator | ||||
|     { | ||||
|         /* HAPPY SCENARIO */ | ||||
| @@ -150,54 +198,6 @@ final class StoredObjectManagerTest extends TestCase | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider getDataProviderForRead | ||||
|      */ | ||||
|     public function testRead(StoredObject $storedObject, string $encodedContent, string $clearContent, ?string $exceptionClass = null) | ||||
|     { | ||||
|         if (null !== $exceptionClass) { | ||||
|             $this->expectException($exceptionClass); | ||||
|         } | ||||
|  | ||||
|         $storedObjectManager = $this->getSubject($storedObject, $encodedContent); | ||||
|  | ||||
|         self::assertEquals($clearContent, $storedObjectManager->read($storedObject)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider getDataProviderForWrite | ||||
|      */ | ||||
|     public function testWrite(StoredObject $storedObject, string $encodedContent, string $clearContent, ?string $exceptionClass = null, ?int $errorCode = null) | ||||
|     { | ||||
|         if (null !== $exceptionClass) { | ||||
|             $this->expectException($exceptionClass); | ||||
|         } | ||||
|  | ||||
|         $previousVersion = $storedObject->getCurrentVersion(); | ||||
|         $previousFilename = $previousVersion->getFilename(); | ||||
|  | ||||
|         $client = new MockHttpClient(function ($method, $url, $options) use ($encodedContent, $previousFilename, $errorCode) { | ||||
|             self::assertEquals('PUT', $method); | ||||
|             self::assertStringStartsWith('https://example.com/', $url); | ||||
|             self::assertStringNotContainsString($previousFilename, $url, 'test that the PUT operation is not performed on the same file'); | ||||
|             self::assertArrayHasKey('body', $options); | ||||
|             self::assertEquals($encodedContent, $options['body']); | ||||
|  | ||||
|             if (-1 === $errorCode) { | ||||
|                 throw new TransportException(); | ||||
|             } | ||||
|  | ||||
|             return new MockResponse('', ['http_code' => $errorCode ?? 201]); | ||||
|         }); | ||||
|  | ||||
|         $storedObjectManager = new StoredObjectManager($client, $this->getTempUrlGenerator($storedObject)); | ||||
|  | ||||
|         $newVersion = $storedObjectManager->write($storedObject, $clearContent); | ||||
|  | ||||
|         self::assertNotSame($previousVersion, $newVersion); | ||||
|         self::assertSame($storedObject->getCurrentVersion(), $newVersion); | ||||
|     } | ||||
|  | ||||
|     public function testDelete(): void | ||||
|     { | ||||
|         $storedObject = new StoredObject(); | ||||
|   | ||||
| @@ -82,6 +82,38 @@ class TempUrlOpenstackGeneratorTest extends KernelTestCase | ||||
|         self::assertEquals($expected, $signedUrl); | ||||
|     } | ||||
|  | ||||
|     public static function dataProviderGenerate(): iterable | ||||
|     { | ||||
|         $now = \DateTimeImmutable::createFromFormat('U', '1702041743'); | ||||
|         $expireDelay = 1800; | ||||
|         $baseUrls = [ | ||||
|             'https://objectstore.example/v1/my_account/container/', | ||||
|             'https://objectstore.example/v1/my_account/container', | ||||
|         ]; | ||||
|         $objectName = 'object'; | ||||
|         $method = 'GET'; | ||||
|         $key = 'MYKEY'; | ||||
|  | ||||
|         $signedUrl = new SignedUrl( | ||||
|             'GET', | ||||
|             'https://objectstore.example/v1/my_account/container/object?temp_url_sig=0aeef353a5f6e22d125c76c6ad8c644a59b222ba1b13eaeb56bf3d04e28b081d11dfcb36601ab3aa7b623d79e1ef03017071bbc842fb7b34afec2baff895bf80&temp_url_expires=1702043543', | ||||
|             \DateTimeImmutable::createFromFormat('U', '1702043543'), | ||||
|             $objectName | ||||
|         ); | ||||
|  | ||||
|         foreach ($baseUrls as $baseUrl) { | ||||
|             yield [ | ||||
|                 $baseUrl, | ||||
|                 $now, | ||||
|                 $key, | ||||
|                 $method, | ||||
|                 $objectName, | ||||
|                 $expireDelay, | ||||
|                 $signedUrl, | ||||
|             ]; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider dataProviderGeneratePost | ||||
|      */ | ||||
| @@ -125,38 +157,6 @@ class TempUrlOpenstackGeneratorTest extends KernelTestCase | ||||
|         self::assertGreaterThanOrEqual(20, strlen($signedUrl->prefix)); | ||||
|     } | ||||
|  | ||||
|     public static function dataProviderGenerate(): iterable | ||||
|     { | ||||
|         $now = \DateTimeImmutable::createFromFormat('U', '1702041743'); | ||||
|         $expireDelay = 1800; | ||||
|         $baseUrls = [ | ||||
|             'https://objectstore.example/v1/my_account/container/', | ||||
|             'https://objectstore.example/v1/my_account/container', | ||||
|         ]; | ||||
|         $objectName = 'object'; | ||||
|         $method = 'GET'; | ||||
|         $key = 'MYKEY'; | ||||
|  | ||||
|         $signedUrl = new SignedUrl( | ||||
|             'GET', | ||||
|             'https://objectstore.example/v1/my_account/container/object?temp_url_sig=0aeef353a5f6e22d125c76c6ad8c644a59b222ba1b13eaeb56bf3d04e28b081d11dfcb36601ab3aa7b623d79e1ef03017071bbc842fb7b34afec2baff895bf80&temp_url_expires=1702043543', | ||||
|             \DateTimeImmutable::createFromFormat('U', '1702043543'), | ||||
|             $objectName | ||||
|         ); | ||||
|  | ||||
|         foreach ($baseUrls as $baseUrl) { | ||||
|             yield [ | ||||
|                 $baseUrl, | ||||
|                 $now, | ||||
|                 $key, | ||||
|                 $method, | ||||
|                 $objectName, | ||||
|                 $expireDelay, | ||||
|                 $signedUrl, | ||||
|             ]; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public static function dataProviderGeneratePost(): iterable | ||||
|     { | ||||
|         $now = \DateTimeImmutable::createFromFormat('U', '1702041743'); | ||||
|   | ||||
| @@ -61,6 +61,55 @@ class StoredObjectContentToLocalStorageControllerTest extends TestCase | ||||
|         $controller->contentOperate($request); | ||||
|     } | ||||
|  | ||||
|     public static function generateOperateContentWithExceptionDataProvider(): iterable | ||||
|     { | ||||
|         yield [ | ||||
|             new Request(['object_name' => '', 'sig' => '', 'exp' => 0]), | ||||
|             BadRequestHttpException::class, | ||||
|             'Object name parameter is missing', | ||||
|             false, | ||||
|             '', | ||||
|             false, | ||||
|         ]; | ||||
|  | ||||
|         yield [ | ||||
|             new Request(['object_name' => 'testABC', 'sig' => '', 'exp' => 0]), | ||||
|             BadRequestHttpException::class, | ||||
|             'Expiration is not set or equal to zero', | ||||
|             false, | ||||
|             '', | ||||
|             false, | ||||
|         ]; | ||||
|  | ||||
|         yield [ | ||||
|             new Request(['object_name' => 'testABC', 'sig' => '', 'exp' => (new \DateTimeImmutable())->getTimestamp()]), | ||||
|             BadRequestHttpException::class, | ||||
|             'Signature is not set or is a blank string', | ||||
|             false, | ||||
|             '', | ||||
|             false, | ||||
|         ]; | ||||
|  | ||||
|         yield [ | ||||
|             new Request(['object_name' => 'testABC', 'sig' => '1234', 'exp' => (new \DateTimeImmutable())->getTimestamp()]), | ||||
|             AccessDeniedHttpException::class, | ||||
|             'Invalid signature', | ||||
|             false, | ||||
|             '', | ||||
|             false, | ||||
|         ]; | ||||
|  | ||||
|  | ||||
|         yield [ | ||||
|             new Request(['object_name' => 'testABC', 'sig' => '1234', 'exp' => (new \DateTimeImmutable())->getTimestamp()]), | ||||
|             NotFoundHttpException::class, | ||||
|             'Object does not exists on disk', | ||||
|             false, | ||||
|             '', | ||||
|             true, | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|     public function testOperateContentGetHappyScenario(): void | ||||
|     { | ||||
|         $objectName = 'testABC'; | ||||
| @@ -286,53 +335,4 @@ class StoredObjectContentToLocalStorageControllerTest extends TestCase | ||||
|             'Filename does not start with signed prefix', | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|     public static function generateOperateContentWithExceptionDataProvider(): iterable | ||||
|     { | ||||
|         yield [ | ||||
|             new Request(['object_name' => '', 'sig' => '', 'exp' => 0]), | ||||
|             BadRequestHttpException::class, | ||||
|             'Object name parameter is missing', | ||||
|             false, | ||||
|             '', | ||||
|             false, | ||||
|         ]; | ||||
|  | ||||
|         yield [ | ||||
|             new Request(['object_name' => 'testABC', 'sig' => '', 'exp' => 0]), | ||||
|             BadRequestHttpException::class, | ||||
|             'Expiration is not set or equal to zero', | ||||
|             false, | ||||
|             '', | ||||
|             false, | ||||
|         ]; | ||||
|  | ||||
|         yield [ | ||||
|             new Request(['object_name' => 'testABC', 'sig' => '', 'exp' => (new \DateTimeImmutable())->getTimestamp()]), | ||||
|             BadRequestHttpException::class, | ||||
|             'Signature is not set or is a blank string', | ||||
|             false, | ||||
|             '', | ||||
|             false, | ||||
|         ]; | ||||
|  | ||||
|         yield [ | ||||
|             new Request(['object_name' => 'testABC', 'sig' => '1234', 'exp' => (new \DateTimeImmutable())->getTimestamp()]), | ||||
|             AccessDeniedHttpException::class, | ||||
|             'Invalid signature', | ||||
|             false, | ||||
|             '', | ||||
|             false, | ||||
|         ]; | ||||
|  | ||||
|  | ||||
|         yield [ | ||||
|             new Request(['object_name' => 'testABC', 'sig' => '1234', 'exp' => (new \DateTimeImmutable())->getTimestamp()]), | ||||
|             NotFoundHttpException::class, | ||||
|             'Object does not exists on disk', | ||||
|             false, | ||||
|             '', | ||||
|             true, | ||||
|         ]; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -136,63 +136,6 @@ class WebdavControllerTest extends KernelTestCase | ||||
|         self::assertXmlStringEqualsXmlString($expectedXmlResponse, $response->getContent(), $message); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider generateDataPropfindDirectory | ||||
|      */ | ||||
|     public function testPropfindDirectory(string $requestContent, int $expectedStatusCode, string $expectedXmlResponse, string $message): void | ||||
|     { | ||||
|         $controller = $this->buildController(); | ||||
|  | ||||
|         $request = new Request([], [], [], [], [], [], $requestContent); | ||||
|         $request->setMethod('PROPFIND'); | ||||
|         $request->headers->add(['Depth' => '0']); | ||||
|         $response = $controller->propfindDirectory($this->buildDocument(), '1234', $request); | ||||
|  | ||||
|         self::assertEquals($expectedStatusCode, $response->getStatusCode()); | ||||
|         self::assertContains('content-type', $response->headers->keys()); | ||||
|         self::assertStringContainsString('text/xml', $response->headers->get('content-type')); | ||||
|         self::assertTrue((new \DOMDocument())->loadXML($response->getContent()), $message.' test that the xml response is a valid xml'); | ||||
|         self::assertXmlStringEqualsXmlString($expectedXmlResponse, $response->getContent(), $message); | ||||
|     } | ||||
|  | ||||
|     public function testHeadDocument(): void | ||||
|     { | ||||
|         $controller = $this->buildController(); | ||||
|         $response = $controller->headDocument($this->buildDocument()); | ||||
|  | ||||
|         self::assertEquals(200, $response->getStatusCode()); | ||||
|         self::assertContains('content-length', $response->headers->keys()); | ||||
|         self::assertContains('content-type', $response->headers->keys()); | ||||
|         self::assertContains('etag', $response->headers->keys()); | ||||
|         self::assertEquals('ab56b4d92b40713acc5af89985d4b786', $response->headers->get('etag')); | ||||
|         self::assertEquals('application/vnd.oasis.opendocument.text', $response->headers->get('content-type')); | ||||
|         self::assertEquals(5, $response->headers->get('content-length')); | ||||
|     } | ||||
|  | ||||
|     public function testPutDocument(): void | ||||
|     { | ||||
|         $document = $this->buildDocument(); | ||||
|         $entityManager = $this->createMock(EntityManagerInterface::class); | ||||
|         $storedObjectManager = $this->createMock(StoredObjectManagerInterface::class); | ||||
|  | ||||
|         // entity manager must be flushed | ||||
|         $entityManager->expects($this->once()) | ||||
|             ->method('flush'); | ||||
|  | ||||
|         // object must be written by StoredObjectManager | ||||
|         $storedObjectManager->expects($this->once()) | ||||
|             ->method('write') | ||||
|             ->with($this->identicalTo($document), $this->identicalTo('1234')); | ||||
|  | ||||
|         $controller = $this->buildController($entityManager, $storedObjectManager); | ||||
|  | ||||
|         $request = new Request(content: '1234'); | ||||
|         $response = $controller->putDocument($document, $request); | ||||
|  | ||||
|         self::assertEquals(204, $response->getStatusCode()); | ||||
|         self::assertEquals('', $response->getContent()); | ||||
|     } | ||||
|  | ||||
|     public static function generateDataPropfindDocument(): iterable | ||||
|     { | ||||
|         $content = | ||||
| @@ -347,6 +290,25 @@ class WebdavControllerTest extends KernelTestCase | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider generateDataPropfindDirectory | ||||
|      */ | ||||
|     public function testPropfindDirectory(string $requestContent, int $expectedStatusCode, string $expectedXmlResponse, string $message): void | ||||
|     { | ||||
|         $controller = $this->buildController(); | ||||
|  | ||||
|         $request = new Request([], [], [], [], [], [], $requestContent); | ||||
|         $request->setMethod('PROPFIND'); | ||||
|         $request->headers->add(['Depth' => '0']); | ||||
|         $response = $controller->propfindDirectory($this->buildDocument(), '1234', $request); | ||||
|  | ||||
|         self::assertEquals($expectedStatusCode, $response->getStatusCode()); | ||||
|         self::assertContains('content-type', $response->headers->keys()); | ||||
|         self::assertStringContainsString('text/xml', $response->headers->get('content-type')); | ||||
|         self::assertTrue((new \DOMDocument())->loadXML($response->getContent()), $message.' test that the xml response is a valid xml'); | ||||
|         self::assertXmlStringEqualsXmlString($expectedXmlResponse, $response->getContent(), $message); | ||||
|     } | ||||
|  | ||||
|     public static function generateDataPropfindDirectory(): iterable | ||||
|     { | ||||
|         yield [ | ||||
| @@ -414,6 +376,44 @@ class WebdavControllerTest extends KernelTestCase | ||||
|             'test creatableContentsInfo', | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|     public function testHeadDocument(): void | ||||
|     { | ||||
|         $controller = $this->buildController(); | ||||
|         $response = $controller->headDocument($this->buildDocument()); | ||||
|  | ||||
|         self::assertEquals(200, $response->getStatusCode()); | ||||
|         self::assertContains('content-length', $response->headers->keys()); | ||||
|         self::assertContains('content-type', $response->headers->keys()); | ||||
|         self::assertContains('etag', $response->headers->keys()); | ||||
|         self::assertEquals('ab56b4d92b40713acc5af89985d4b786', $response->headers->get('etag')); | ||||
|         self::assertEquals('application/vnd.oasis.opendocument.text', $response->headers->get('content-type')); | ||||
|         self::assertEquals(5, $response->headers->get('content-length')); | ||||
|     } | ||||
|  | ||||
|     public function testPutDocument(): void | ||||
|     { | ||||
|         $document = $this->buildDocument(); | ||||
|         $entityManager = $this->createMock(EntityManagerInterface::class); | ||||
|         $storedObjectManager = $this->createMock(StoredObjectManagerInterface::class); | ||||
|  | ||||
|         // entity manager must be flushed | ||||
|         $entityManager->expects($this->once()) | ||||
|             ->method('flush'); | ||||
|  | ||||
|         // object must be written by StoredObjectManager | ||||
|         $storedObjectManager->expects($this->once()) | ||||
|             ->method('write') | ||||
|             ->with($this->identicalTo($document), $this->identicalTo('1234')); | ||||
|  | ||||
|         $controller = $this->buildController($entityManager, $storedObjectManager); | ||||
|  | ||||
|         $request = new Request(content: '1234'); | ||||
|         $response = $controller->putDocument($document, $request); | ||||
|  | ||||
|         self::assertEquals(204, $response->getStatusCode()); | ||||
|         self::assertEquals('', $response->getContent()); | ||||
|     } | ||||
| } | ||||
|  | ||||
| class MockedStoredObjectManager implements StoredObjectManagerInterface | ||||
|   | ||||
| @@ -87,6 +87,16 @@ class PersonDocumentACLAwareRepositoryTest extends KernelTestCase | ||||
|         self::assertIsInt($nb, 'test that the query could be executed'); | ||||
|     } | ||||
|  | ||||
|     public static function provideDataBuildFetchQueryForPerson(): iterable | ||||
|     { | ||||
|         yield [null, null, null]; | ||||
|         yield [new \DateTimeImmutable('1 year ago'), null, null]; | ||||
|         yield [null, new \DateTimeImmutable('1 year ago'), null]; | ||||
|         yield [new \DateTimeImmutable('2 years ago'), new \DateTimeImmutable('1 year ago'), null]; | ||||
|         yield [null, null, 'test']; | ||||
|         yield [new \DateTimeImmutable('2 years ago'), new \DateTimeImmutable('1 year ago'), 'test']; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider provideDateForFetchQueryForAccompanyingPeriod | ||||
|      */ | ||||
| @@ -142,14 +152,4 @@ class PersonDocumentACLAwareRepositoryTest extends KernelTestCase | ||||
|         yield [$period, null, null, 'test']; | ||||
|         yield [$period, new \DateTimeImmutable('2 years ago'), new \DateTimeImmutable('1 year ago'), 'test']; | ||||
|     } | ||||
|  | ||||
|     public static function provideDataBuildFetchQueryForPerson(): iterable | ||||
|     { | ||||
|         yield [null, null, null]; | ||||
|         yield [new \DateTimeImmutable('1 year ago'), null, null]; | ||||
|         yield [null, new \DateTimeImmutable('1 year ago'), null]; | ||||
|         yield [new \DateTimeImmutable('2 years ago'), new \DateTimeImmutable('1 year ago'), null]; | ||||
|         yield [null, null, 'test']; | ||||
|         yield [new \DateTimeImmutable('2 years ago'), new \DateTimeImmutable('1 year ago'), 'test']; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -50,19 +50,6 @@ class StoredObjectVoterTest extends TestCase | ||||
|         self::assertEquals($expected, $voter->vote($token, $subject, [$attribute])); | ||||
|     } | ||||
|  | ||||
|     private function buildStoredObjectVoter(bool $supportsIsCalled, bool $supports, bool $voteOnAttribute): StoredObjectVoterInterface | ||||
|     { | ||||
|         $storedObjectVoter = $this->createMock(StoredObjectVoterInterface::class); | ||||
|         $storedObjectVoter->expects($supportsIsCalled ? $this->once() : $this->never())->method('supports') | ||||
|             ->with(self::isInstanceOf(StoredObjectRoleEnum::class), $this->isInstanceOf(StoredObject::class)) | ||||
|             ->willReturn($supports); | ||||
|         $storedObjectVoter->expects($supportsIsCalled && $supports ? $this->once() : $this->never())->method('voteOnAttribute') | ||||
|             ->with(self::isInstanceOf(StoredObjectRoleEnum::class), $this->isInstanceOf(StoredObject::class), $this->isInstanceOf(TokenInterface::class)) | ||||
|             ->willReturn($voteOnAttribute); | ||||
|  | ||||
|         return $storedObjectVoter; | ||||
|     } | ||||
|  | ||||
|     public static function provideDataVote(): iterable | ||||
|     { | ||||
|         yield [ | ||||
| @@ -120,4 +107,17 @@ class StoredObjectVoterTest extends TestCase | ||||
|             VoterInterface::ACCESS_GRANTED, | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|     private function buildStoredObjectVoter(bool $supportsIsCalled, bool $supports, bool $voteOnAttribute): StoredObjectVoterInterface | ||||
|     { | ||||
|         $storedObjectVoter = $this->createMock(StoredObjectVoterInterface::class); | ||||
|         $storedObjectVoter->expects($supportsIsCalled ? $this->once() : $this->never())->method('supports') | ||||
|             ->with(self::isInstanceOf(StoredObjectRoleEnum::class), $this->isInstanceOf(StoredObject::class)) | ||||
|             ->willReturn($supports); | ||||
|         $storedObjectVoter->expects($supportsIsCalled && $supports ? $this->once() : $this->never())->method('voteOnAttribute') | ||||
|             ->with(self::isInstanceOf(StoredObjectRoleEnum::class), $this->isInstanceOf(StoredObject::class), $this->isInstanceOf(TokenInterface::class)) | ||||
|             ->willReturn($voteOnAttribute); | ||||
|  | ||||
|         return $storedObjectVoter; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -40,29 +40,6 @@ class RemoveOldVersionCronJobTest extends KernelTestCase | ||||
|         self::assertEquals($expected, $cronJob->canRun($cronJobExecution)); | ||||
|     } | ||||
|  | ||||
|     public function testRun(): void | ||||
|     { | ||||
|         // we create a clock in the future. This led us a chance to having stored object to delete | ||||
|         $clock = new MockClock(new \DateTimeImmutable('2024-01-01 00:00:00', new \DateTimeZone('+00:00'))); | ||||
|         $repository = $this->createMock(StoredObjectVersionRepository::class); | ||||
|         $repository->expects($this->once()) | ||||
|             ->method('findIdsByVersionsOlderThanDateAndNotLastVersionAndNotPointInTime') | ||||
|             ->with(new \DateTime('2023-10-03 00:00:00', new \DateTimeZone('+00:00'))) | ||||
|             ->willReturnCallback(function ($arg) { | ||||
|                 yield 1; | ||||
|                 yield 3; | ||||
|                 yield 2; | ||||
|             }) | ||||
|         ; | ||||
|  | ||||
|         $cronJob = new RemoveOldVersionCronJob($clock, $this->buildMessageBus(true), $repository); | ||||
|  | ||||
|         $results = $cronJob->run([]); | ||||
|  | ||||
|         self::assertArrayHasKey('last-deleted-stored-object-version-id', $results); | ||||
|         self::assertIsInt($results['last-deleted-stored-object-version-id']); | ||||
|     } | ||||
|  | ||||
|     public static function buildTestCanRunData(): iterable | ||||
|     { | ||||
|         yield [ | ||||
| @@ -86,6 +63,29 @@ class RemoveOldVersionCronJobTest extends KernelTestCase | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|     public function testRun(): void | ||||
|     { | ||||
|         // we create a clock in the future. This led us a chance to having stored object to delete | ||||
|         $clock = new MockClock(new \DateTimeImmutable('2024-01-01 00:00:00', new \DateTimeZone('+00:00'))); | ||||
|         $repository = $this->createMock(StoredObjectVersionRepository::class); | ||||
|         $repository->expects($this->once()) | ||||
|             ->method('findIdsByVersionsOlderThanDateAndNotLastVersionAndNotPointInTime') | ||||
|             ->with(new \DateTime('2023-10-03 00:00:00', new \DateTimeZone('+00:00'))) | ||||
|             ->willReturnCallback(function ($arg) { | ||||
|                 yield 1; | ||||
|                 yield 3; | ||||
|                 yield 2; | ||||
|             }) | ||||
|         ; | ||||
|  | ||||
|         $cronJob = new RemoveOldVersionCronJob($clock, $this->buildMessageBus(true), $repository); | ||||
|  | ||||
|         $results = $cronJob->run([]); | ||||
|  | ||||
|         self::assertArrayHasKey('last-deleted-stored-object-version-id', $results); | ||||
|         self::assertIsInt($results['last-deleted-stored-object-version-id']); | ||||
|     } | ||||
|  | ||||
|     private function buildMessageBus(bool $expectDistpatchAtLeastOnce = false): MessageBusInterface | ||||
|     { | ||||
|         $messageBus = $this->createMock(MessageBusInterface::class); | ||||
|   | ||||
| @@ -70,9 +70,9 @@ class NewsItem implements TrackCreationInterface, TrackUpdateInterface | ||||
|         return $this->content; | ||||
|     } | ||||
|  | ||||
|     public function setContent(string $content): void | ||||
|     public function setContent(?string $content): void | ||||
|     { | ||||
|         $this->content = $content; | ||||
|         $this->content = (string) $content; | ||||
|     } | ||||
|  | ||||
|     public function getStartDate(): ?\DateTimeImmutable | ||||
|   | ||||
| @@ -58,7 +58,6 @@ final readonly class CancelStaleWorkflowHandler | ||||
|         $transitions = $workflowComponent->getEnabledTransitions($workflow); | ||||
|  | ||||
|         $transitionApplied = false; | ||||
|         $wasInInitialPosition = 'initial' === $workflow->getStep(); | ||||
|  | ||||
|         foreach ($transitions as $transition) { | ||||
|             if ($this->willTransitionLeadToFinalNegative($transition, $metadataStore)) { | ||||
| @@ -80,10 +79,6 @@ final readonly class CancelStaleWorkflowHandler | ||||
|             throw new UnrecoverableMessageHandlingException(sprintf('No valid transition found for EntityWorkflow %d.', $workflowId)); | ||||
|         } | ||||
|  | ||||
|         if ($wasInInitialPosition) { | ||||
|             $this->em->remove($workflow); | ||||
|         } | ||||
|  | ||||
|         $this->em->flush(); | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -32,107 +32,6 @@ abstract class AbstractAggregatorTest extends KernelTestCase | ||||
|         self::ensureKernelShutdown(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * provide data for `testAliasDidNotDisappears`. | ||||
|      */ | ||||
|     public static function dataProviderAliasDidNotDisappears() | ||||
|     { | ||||
|         $datas = static::getFormData(); | ||||
|  | ||||
|         if (!\is_array($datas)) { | ||||
|             $datas = iterator_to_array($datas); | ||||
|         } | ||||
|  | ||||
|         foreach (static::getQueryBuilders() as $qb) { | ||||
|             if ([] === $datas) { | ||||
|                 yield [clone $qb, []]; | ||||
|             } else { | ||||
|                 foreach (static::getFormData() as $data) { | ||||
|                     yield [clone $qb, $data]; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * provide data for `testAlterQuery`. | ||||
|      */ | ||||
|     public static function dataProviderAlterQuery() | ||||
|     { | ||||
|         $datas = static::getFormData(); | ||||
|  | ||||
|         if (!\is_array($datas)) { | ||||
|             $datas = iterator_to_array($datas); | ||||
|         } | ||||
|  | ||||
|         foreach (static::getQueryBuilders() as $qb) { | ||||
|             if ([] === $datas) { | ||||
|                 yield [clone $qb, []]; | ||||
|             } else { | ||||
|                 foreach (static::getFormData() as $data) { | ||||
|                     yield [clone $qb, $data]; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public static function dataProviderQueryExecution(): iterable | ||||
|     { | ||||
|         $datas = static::getFormData(); | ||||
|  | ||||
|         if (!\is_array($datas)) { | ||||
|             $datas = iterator_to_array($datas); | ||||
|         } | ||||
|  | ||||
|         foreach (static::getQueryBuilders() as $qb) { | ||||
|             if ([] === $datas) { | ||||
|                 yield [clone $qb, []]; | ||||
|             } else { | ||||
|                 foreach (static::getFormData() as $data) { | ||||
|                     yield [clone $qb, $data]; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * prepare data for `testGetQueryKeys`. | ||||
|      */ | ||||
|     public static function dataProviderGetQueryKeys() | ||||
|     { | ||||
|         $datas = static::getFormData(); | ||||
|  | ||||
|         if (!\is_array($datas)) { | ||||
|             $datas = iterator_to_array($datas); | ||||
|         } | ||||
|  | ||||
|         foreach ($datas as $data) { | ||||
|             yield [$data]; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * prepare date for method `testGetResultsAndLabels`. | ||||
|      */ | ||||
|     public static function dataProviderGetResultsAndLabels() | ||||
|     { | ||||
|         $datas = static::getFormData(); | ||||
|  | ||||
|         if (!\is_array($datas)) { | ||||
|             $datas = iterator_to_array($datas); | ||||
|         } | ||||
|  | ||||
|         foreach (static::getQueryBuilders() as $qb) { | ||||
|             if ([] === $datas) { | ||||
|                 yield [clone $qb, []]; | ||||
|             } else { | ||||
|                 foreach ($datas as $data) { | ||||
|                     yield [clone $qb, $data]; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Create an aggregator instance which will be used in tests. | ||||
|      * | ||||
| @@ -187,6 +86,28 @@ abstract class AbstractAggregatorTest extends KernelTestCase | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * provide data for `testAliasDidNotDisappears`. | ||||
|      */ | ||||
|     public static function dataProviderAliasDidNotDisappears() | ||||
|     { | ||||
|         $datas = static::getFormData(); | ||||
|  | ||||
|         if (!\is_array($datas)) { | ||||
|             $datas = iterator_to_array($datas); | ||||
|         } | ||||
|  | ||||
|         foreach (static::getQueryBuilders() as $qb) { | ||||
|             if ([] === $datas) { | ||||
|                 yield [clone $qb, []]; | ||||
|             } else { | ||||
|                 foreach (static::getFormData() as $data) { | ||||
|                     yield [clone $qb, $data]; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider dataProviderQueryExecution | ||||
|      * | ||||
| @@ -201,6 +122,25 @@ abstract class AbstractAggregatorTest extends KernelTestCase | ||||
|         self::assertIsArray($actual); | ||||
|     } | ||||
|  | ||||
|     public static function dataProviderQueryExecution(): iterable | ||||
|     { | ||||
|         $datas = static::getFormData(); | ||||
|  | ||||
|         if (!\is_array($datas)) { | ||||
|             $datas = iterator_to_array($datas); | ||||
|         } | ||||
|  | ||||
|         foreach (static::getQueryBuilders() as $qb) { | ||||
|             if ([] === $datas) { | ||||
|                 yield [clone $qb, []]; | ||||
|             } else { | ||||
|                 foreach (static::getFormData() as $data) { | ||||
|                     yield [clone $qb, $data]; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * test the alteration of query by the filter. | ||||
|      * | ||||
| @@ -239,6 +179,28 @@ abstract class AbstractAggregatorTest extends KernelTestCase | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * provide data for `testAlterQuery`. | ||||
|      */ | ||||
|     public static function dataProviderAlterQuery() | ||||
|     { | ||||
|         $datas = static::getFormData(); | ||||
|  | ||||
|         if (!\is_array($datas)) { | ||||
|             $datas = iterator_to_array($datas); | ||||
|         } | ||||
|  | ||||
|         foreach (static::getQueryBuilders() as $qb) { | ||||
|             if ([] === $datas) { | ||||
|                 yield [clone $qb, []]; | ||||
|             } else { | ||||
|                 foreach (static::getFormData() as $data) { | ||||
|                     yield [clone $qb, $data]; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Test the `applyOn` method. | ||||
|      */ | ||||
| @@ -282,6 +244,22 @@ abstract class AbstractAggregatorTest extends KernelTestCase | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * prepare data for `testGetQueryKeys`. | ||||
|      */ | ||||
|     public static function dataProviderGetQueryKeys() | ||||
|     { | ||||
|         $datas = static::getFormData(); | ||||
|  | ||||
|         if (!\is_array($datas)) { | ||||
|             $datas = iterator_to_array($datas); | ||||
|         } | ||||
|  | ||||
|         foreach ($datas as $data) { | ||||
|             yield [$data]; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Test that. | ||||
|      * | ||||
| @@ -346,6 +324,28 @@ abstract class AbstractAggregatorTest extends KernelTestCase | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * prepare date for method `testGetResultsAndLabels`. | ||||
|      */ | ||||
|     public static function dataProviderGetResultsAndLabels() | ||||
|     { | ||||
|         $datas = static::getFormData(); | ||||
|  | ||||
|         if (!\is_array($datas)) { | ||||
|             $datas = iterator_to_array($datas); | ||||
|         } | ||||
|  | ||||
|         foreach (static::getQueryBuilders() as $qb) { | ||||
|             if ([] === $datas) { | ||||
|                 yield [clone $qb, []]; | ||||
|             } else { | ||||
|                 foreach ($datas as $data) { | ||||
|                     yield [clone $qb, $data]; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * test the `getTitle` method. | ||||
|      */ | ||||
|   | ||||
| @@ -31,27 +31,6 @@ abstract class AbstractExportTest extends WebTestCase | ||||
| { | ||||
|     use PrepareClientTrait; | ||||
|  | ||||
|     public static function dataProviderGetQueryKeys() | ||||
|     { | ||||
|         foreach (static::getFormData() as $data) { | ||||
|             yield [$data]; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * create data for `ìnitiateQuery` method. | ||||
|      */ | ||||
|     public static function dataProviderInitiateQuery() | ||||
|     { | ||||
|         $acl = static::getAcl(); | ||||
|  | ||||
|         foreach (static::getModifiersCombination() as $modifiers) { | ||||
|             foreach (static::getFormData() as $data) { | ||||
|                 yield [$modifiers, $acl, $data]; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Return an array usable as ACL. | ||||
|      * | ||||
| @@ -198,6 +177,13 @@ abstract class AbstractExportTest extends WebTestCase | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public static function dataProviderGetQueryKeys() | ||||
|     { | ||||
|         foreach (static::getFormData() as $data) { | ||||
|             yield [$data]; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Test that. | ||||
|      * | ||||
| @@ -382,4 +368,18 @@ abstract class AbstractExportTest extends WebTestCase | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * create data for `ìnitiateQuery` method. | ||||
|      */ | ||||
|     public static function dataProviderInitiateQuery() | ||||
|     { | ||||
|         $acl = static::getAcl(); | ||||
|  | ||||
|         foreach (static::getModifiersCombination() as $modifiers) { | ||||
|             foreach (static::getFormData() as $data) { | ||||
|                 yield [$modifiers, $acl, $data]; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -43,61 +43,6 @@ abstract class AbstractFilterTest extends KernelTestCase | ||||
|         self::ensureKernelShutdown(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * provide data for `testAliasDidNotDisappears`. | ||||
|      */ | ||||
|     public static function dataProviderAliasDidNotDisappears() | ||||
|     { | ||||
|         $datas = static::getFormData(); | ||||
|  | ||||
|         foreach (static::getQueryBuilders() as $qb) { | ||||
|             if ([] === $datas) { | ||||
|                 yield [clone $qb, []]; | ||||
|             } else { | ||||
|                 foreach ($datas as $data) { | ||||
|                     yield [clone $qb, $data]; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public static function dataProviderAlterQuery() | ||||
|     { | ||||
|         $datas = static::getFormData(); | ||||
|  | ||||
|         foreach (static::getQueryBuilders() as $qb) { | ||||
|             if ([] === $datas) { | ||||
|                 yield [clone $qb, []]; | ||||
|             } else { | ||||
|                 foreach ($datas as $data) { | ||||
|                     yield [clone $qb, $data]; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public static function dataProvideQueryExecution(): iterable | ||||
|     { | ||||
|         $datas = static::getFormData(); | ||||
|  | ||||
|         foreach (static::getQueryBuilders() as $qb) { | ||||
|             if ([] === $datas) { | ||||
|                 yield [clone $qb, []]; | ||||
|             } else { | ||||
|                 foreach ($datas as $data) { | ||||
|                     yield [clone $qb, $data]; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public static function dataProviderDescriptionAction() | ||||
|     { | ||||
|         foreach (static::getFormData() as $data) { | ||||
|             yield [$data]; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Create a filter which will be used in tests. | ||||
|      * | ||||
| @@ -149,6 +94,24 @@ abstract class AbstractFilterTest extends KernelTestCase | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * provide data for `testAliasDidNotDisappears`. | ||||
|      */ | ||||
|     public static function dataProviderAliasDidNotDisappears() | ||||
|     { | ||||
|         $datas = static::getFormData(); | ||||
|  | ||||
|         foreach (static::getQueryBuilders() as $qb) { | ||||
|             if ([] === $datas) { | ||||
|                 yield [clone $qb, []]; | ||||
|             } else { | ||||
|                 foreach ($datas as $data) { | ||||
|                     yield [clone $qb, $data]; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * test the alteration of query by the filter. | ||||
|      * | ||||
| @@ -187,6 +150,21 @@ abstract class AbstractFilterTest extends KernelTestCase | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     public static function dataProviderAlterQuery() | ||||
|     { | ||||
|         $datas = static::getFormData(); | ||||
|  | ||||
|         foreach (static::getQueryBuilders() as $qb) { | ||||
|             if ([] === $datas) { | ||||
|                 yield [clone $qb, []]; | ||||
|             } else { | ||||
|                 foreach ($datas as $data) { | ||||
|                     yield [clone $qb, $data]; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider dataProvideQueryExecution | ||||
|      */ | ||||
| @@ -199,6 +177,21 @@ abstract class AbstractFilterTest extends KernelTestCase | ||||
|         self::assertIsArray($actual); | ||||
|     } | ||||
|  | ||||
|     public static function dataProvideQueryExecution(): iterable | ||||
|     { | ||||
|         $datas = static::getFormData(); | ||||
|  | ||||
|         foreach (static::getQueryBuilders() as $qb) { | ||||
|             if ([] === $datas) { | ||||
|                 yield [clone $qb, []]; | ||||
|             } else { | ||||
|                 foreach ($datas as $data) { | ||||
|                     yield [clone $qb, $data]; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public function testApplyOn() | ||||
|     { | ||||
|         $filter = $this->getFilter(); | ||||
| @@ -263,6 +256,13 @@ abstract class AbstractFilterTest extends KernelTestCase | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public static function dataProviderDescriptionAction() | ||||
|     { | ||||
|         foreach (static::getFormData() as $data) { | ||||
|             yield [$data]; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public function testGetTitle() | ||||
|     { | ||||
|         $title = $this->getFilter()->getTitle(); | ||||
|   | ||||
| @@ -32,6 +32,17 @@ final class AddressControllerTest extends \Symfony\Bundle\FrameworkBundle\Test\W | ||||
|         self::ensureKernelShutdown(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider generateAddressIds | ||||
|      */ | ||||
|     public function testDuplicate(int $addressId) | ||||
|     { | ||||
|         $this->client = $this->getClientAuthenticated(); | ||||
|         $this->client->request('POST', "/api/1.0/main/address/{$addressId}/duplicate.json"); | ||||
|  | ||||
|         $this->assertResponseIsSuccessful('test that duplicate is successful'); | ||||
|     } | ||||
|  | ||||
|     public static function generateAddressIds(): iterable | ||||
|     { | ||||
|         self::bootKernel(); | ||||
| @@ -49,15 +60,4 @@ final class AddressControllerTest extends \Symfony\Bundle\FrameworkBundle\Test\W | ||||
|  | ||||
|         self::ensureKernelShutdown(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider generateAddressIds | ||||
|      */ | ||||
|     public function testDuplicate(int $addressId) | ||||
|     { | ||||
|         $this->client = $this->getClientAuthenticated(); | ||||
|         $this->client->request('POST', "/api/1.0/main/address/{$addressId}/duplicate.json"); | ||||
|  | ||||
|         $this->assertResponseIsSuccessful('test that duplicate is successful'); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -25,6 +25,22 @@ final class AddressReferenceApiControllerTest extends WebTestCase | ||||
| { | ||||
|     use PrepareClientTrait; | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider provideData | ||||
|      */ | ||||
|     public function testSearch(int $postCodeId, string $pattern) | ||||
|     { | ||||
|         $client = $this->getClientAuthenticated(); | ||||
|  | ||||
|         $client->request( | ||||
|             'GET', | ||||
|             "/api/1.0/main/address-reference/by-postal-code/{$postCodeId}/search.json", | ||||
|             ['q' => $pattern] | ||||
|         ); | ||||
|  | ||||
|         $this->assertResponseIsSuccessful(); | ||||
|     } | ||||
|  | ||||
|     public static function provideData() | ||||
|     { | ||||
|         self::bootKernel(); | ||||
| @@ -42,20 +58,4 @@ final class AddressReferenceApiControllerTest extends WebTestCase | ||||
|  | ||||
|         yield [$postalCode->getId(), 'rue']; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider provideData | ||||
|      */ | ||||
|     public function testSearch(int $postCodeId, string $pattern) | ||||
|     { | ||||
|         $client = $this->getClientAuthenticated(); | ||||
|  | ||||
|         $client->request( | ||||
|             'GET', | ||||
|             "/api/1.0/main/address-reference/by-postal-code/{$postCodeId}/search.json", | ||||
|             ['q' => $pattern] | ||||
|         ); | ||||
|  | ||||
|         $this->assertResponseIsSuccessful(); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -52,26 +52,6 @@ class AddressToReferenceMatcherControllerTest extends WebTestCase | ||||
|         $this->assertEquals(Address::ADDR_REFERENCE_STATUS_REVIEWED, $address->getRefStatus()); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider addressUnsyncedProvider | ||||
|      */ | ||||
|     public function testSyncAddressWithReference(int $addressId): void | ||||
|     { | ||||
|         $client = $this->getClientAuthenticated(); | ||||
|  | ||||
|         $client->request('POST', "/api/1.0/main/address/reference-match/{$addressId}/sync-with-reference"); | ||||
|  | ||||
|         $this->assertResponseIsSuccessful(); | ||||
|  | ||||
|         $this->addressRepository = self::getContainer()->get(AddressRepository::class); | ||||
|         $address = $this->addressRepository->find($addressId); | ||||
|  | ||||
|         $this->assertEquals(Address::ADDR_REFERENCE_STATUS_MATCH, $address->getRefStatus()); | ||||
|         $this->assertEquals($address->getAddressReference()->getStreet(), $address->getStreet()); | ||||
|         $this->assertEquals($address->getAddressReference()->getStreetNumber(), $address->getStreetNumber()); | ||||
|         $this->assertEquals($address->getAddressReference()->getPoint()->toWKT(), $address->getPoint()->toWKT()); | ||||
|     } | ||||
|  | ||||
|     public static function addressToReviewProvider(): iterable | ||||
|     { | ||||
|         self::bootKernel(); | ||||
| @@ -98,6 +78,26 @@ class AddressToReferenceMatcherControllerTest extends WebTestCase | ||||
|         self::ensureKernelShutdown(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider addressUnsyncedProvider | ||||
|      */ | ||||
|     public function testSyncAddressWithReference(int $addressId): void | ||||
|     { | ||||
|         $client = $this->getClientAuthenticated(); | ||||
|  | ||||
|         $client->request('POST', "/api/1.0/main/address/reference-match/{$addressId}/sync-with-reference"); | ||||
|  | ||||
|         $this->assertResponseIsSuccessful(); | ||||
|  | ||||
|         $this->addressRepository = self::getContainer()->get(AddressRepository::class); | ||||
|         $address = $this->addressRepository->find($addressId); | ||||
|  | ||||
|         $this->assertEquals(Address::ADDR_REFERENCE_STATUS_MATCH, $address->getRefStatus()); | ||||
|         $this->assertEquals($address->getAddressReference()->getStreet(), $address->getStreet()); | ||||
|         $this->assertEquals($address->getAddressReference()->getStreetNumber(), $address->getStreetNumber()); | ||||
|         $this->assertEquals($address->getAddressReference()->getPoint()->toWKT(), $address->getPoint()->toWKT()); | ||||
|     } | ||||
|  | ||||
|     public static function addressUnsyncedProvider(): iterable | ||||
|     { | ||||
|         self::bootKernel(); | ||||
|   | ||||
| @@ -55,6 +55,25 @@ class NewsItemControllerTest extends WebTestCase | ||||
|         $em->flush(); | ||||
|     } | ||||
|  | ||||
|     public function testList() | ||||
|     { | ||||
|         $client = $this->getClientAuthenticated('admin', 'password'); | ||||
|         $client->request('GET', '/fr/admin/news_item'); | ||||
|  | ||||
|         self::assertResponseIsSuccessful('News item admin page shows'); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider generateNewsItemIds | ||||
|      */ | ||||
|     public function testShowSingleItem(NewsItem $newsItem) | ||||
|     { | ||||
|         $client = $this->getClientAuthenticated('admin', 'password'); | ||||
|         $client->request('GET', "/fr/admin/news_item/{$newsItem->getId()}/view"); | ||||
|  | ||||
|         self::assertResponseIsSuccessful('Single news item admin page loads successfully'); | ||||
|     } | ||||
|  | ||||
|     public static function generateNewsItemIds(): iterable | ||||
|     { | ||||
|         self::bootKernel(); | ||||
| @@ -74,23 +93,4 @@ class NewsItemControllerTest extends WebTestCase | ||||
|  | ||||
|         yield [$newsItem]; | ||||
|     } | ||||
|  | ||||
|     public function testList() | ||||
|     { | ||||
|         $client = $this->getClientAuthenticated('admin', 'password'); | ||||
|         $client->request('GET', '/fr/admin/news_item'); | ||||
|  | ||||
|         self::assertResponseIsSuccessful('News item admin page shows'); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider generateNewsItemIds | ||||
|      */ | ||||
|     public function testShowSingleItem(NewsItem $newsItem) | ||||
|     { | ||||
|         $client = $this->getClientAuthenticated('admin', 'password'); | ||||
|         $client->request('GET', "/fr/admin/news_item/{$newsItem->getId()}/view"); | ||||
|  | ||||
|         self::assertResponseIsSuccessful('Single news item admin page loads successfully'); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -51,27 +51,6 @@ class NewsItemsHistoryControllerTest extends WebTestCase | ||||
|         self::ensureKernelShutdown(); | ||||
|     } | ||||
|  | ||||
|     public static function generateNewsItemIds(): iterable | ||||
|     { | ||||
|         self::bootKernel(); | ||||
|         $em = self::getContainer()->get(EntityManagerInterface::class); | ||||
|  | ||||
|         $news = new NewsItem(); | ||||
|  | ||||
|         $news->setContent('test content'); | ||||
|         $news->setTitle('Title'); | ||||
|         $news->setStartDate(new \DateTimeImmutable('yesterday')); | ||||
|  | ||||
|         $em->persist($news); | ||||
|         $em->flush(); | ||||
|  | ||||
|         static::$toDelete[] = [NewsItem::class, $news]; | ||||
|  | ||||
|         self::ensureKernelShutdown(); | ||||
|  | ||||
|         yield [$news->getId()]; | ||||
|     } | ||||
|  | ||||
|     public function testList() | ||||
|     { | ||||
|         self::ensureKernelShutdown(); | ||||
| @@ -94,4 +73,25 @@ class NewsItemsHistoryControllerTest extends WebTestCase | ||||
|  | ||||
|         $this->assertResponseIsSuccessful('test that single news item page loads successfully'); | ||||
|     } | ||||
|  | ||||
|     public static function generateNewsItemIds(): iterable | ||||
|     { | ||||
|         self::bootKernel(); | ||||
|         $em = self::getContainer()->get(EntityManagerInterface::class); | ||||
|  | ||||
|         $news = new NewsItem(); | ||||
|  | ||||
|         $news->setContent('test content'); | ||||
|         $news->setTitle('Title'); | ||||
|         $news->setStartDate(new \DateTimeImmutable('yesterday')); | ||||
|  | ||||
|         $em->persist($news); | ||||
|         $em->flush(); | ||||
|  | ||||
|         static::$toDelete[] = [NewsItem::class, $news]; | ||||
|  | ||||
|         self::ensureKernelShutdown(); | ||||
|  | ||||
|         yield [$news->getId()]; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -44,33 +44,6 @@ final class NotificationApiControllerTest extends WebTestCase | ||||
|         self::$toDelete = []; | ||||
|     } | ||||
|  | ||||
|     public static function generateDataMarkAsRead() | ||||
|     { | ||||
|         self::bootKernel(); | ||||
|         $em = self::getContainer()->get(EntityManagerInterface::class); | ||||
|         $userRepository = self::getContainer()->get(UserRepository::class); | ||||
|         $userA = $userRepository->findOneBy(['username' => 'center a_social']); | ||||
|         $userB = $userRepository->findOneBy(['username' => 'center b_social']); | ||||
|  | ||||
|         $notification = new Notification(); | ||||
|         $notification | ||||
|             ->setMessage('Test generated') | ||||
|             ->setRelatedEntityClass(AccompanyingPeriod::class) | ||||
|             ->setRelatedEntityId(0) | ||||
|             ->setSender($userB) | ||||
|             ->addAddressee($userA) | ||||
|             ->setUpdatedAt(new \DateTimeImmutable()); | ||||
|         $em->persist($notification); | ||||
|         $em->refresh($notification); | ||||
|         $em->flush(); | ||||
|  | ||||
|         self::$toDelete[] = [Notification::class, $notification->getId()]; | ||||
|  | ||||
|         self::ensureKernelShutdown(); | ||||
|  | ||||
|         yield [$notification->getId()]; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider generateDataMarkAsRead | ||||
|      */ | ||||
| @@ -99,4 +72,31 @@ final class NotificationApiControllerTest extends WebTestCase | ||||
|  | ||||
|         $this->assertFalse($notification->isReadBy($user)); | ||||
|     } | ||||
|  | ||||
|     public static function generateDataMarkAsRead() | ||||
|     { | ||||
|         self::bootKernel(); | ||||
|         $em = self::getContainer()->get(EntityManagerInterface::class); | ||||
|         $userRepository = self::getContainer()->get(UserRepository::class); | ||||
|         $userA = $userRepository->findOneBy(['username' => 'center a_social']); | ||||
|         $userB = $userRepository->findOneBy(['username' => 'center b_social']); | ||||
|  | ||||
|         $notification = new Notification(); | ||||
|         $notification | ||||
|             ->setMessage('Test generated') | ||||
|             ->setRelatedEntityClass(AccompanyingPeriod::class) | ||||
|             ->setRelatedEntityId(0) | ||||
|             ->setSender($userB) | ||||
|             ->addAddressee($userA) | ||||
|             ->setUpdatedAt(new \DateTimeImmutable()); | ||||
|         $em->persist($notification); | ||||
|         $em->refresh($notification); | ||||
|         $em->flush(); | ||||
|  | ||||
|         self::$toDelete[] = [Notification::class, $notification->getId()]; | ||||
|  | ||||
|         self::ensureKernelShutdown(); | ||||
|  | ||||
|         yield [$notification->getId()]; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -24,17 +24,6 @@ final class SearchApiControllerTest extends WebTestCase | ||||
| { | ||||
|     use PrepareClientTrait; | ||||
|  | ||||
|     public static function generateSearchData() | ||||
|     { | ||||
|         yield ['per', ['person', 'thirdparty']]; | ||||
|  | ||||
|         yield ['per', ['thirdparty']]; | ||||
|  | ||||
|         yield ['per', ['person']]; | ||||
|  | ||||
|         yield ['fjklmeqjfkdqjklrmefdqjklm', ['person', 'thirdparty']]; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider generateSearchData | ||||
|      */ | ||||
| @@ -50,4 +39,15 @@ final class SearchApiControllerTest extends WebTestCase | ||||
|  | ||||
|         $this->assertResponseIsSuccessful(); | ||||
|     } | ||||
|  | ||||
|     public static function generateSearchData() | ||||
|     { | ||||
|         yield ['per', ['person', 'thirdparty']]; | ||||
|  | ||||
|         yield ['per', ['thirdparty']]; | ||||
|  | ||||
|         yield ['per', ['person']]; | ||||
|  | ||||
|         yield ['fjklmeqjfkdqjklrmefdqjklm', ['person', 'thirdparty']]; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -27,25 +27,6 @@ final class UserControllerTest extends WebTestCase | ||||
| { | ||||
|     use PrepareClientTrait; | ||||
|  | ||||
|     public static function dataGenerateUserId() | ||||
|     { | ||||
|         self::bootKernel(); | ||||
|         $em = self::getContainer()->get(EntityManagerInterface::class); | ||||
|         /** @var UserPasswordHasherInterface::class $passwordHasher */ | ||||
|         $passwordHasher = self::getContainer()->get(UserPasswordHasherInterface::class); | ||||
|  | ||||
|         $user = new User(); | ||||
|         $user->setUsername('Test_user '.uniqid()); | ||||
|         $user->setPassword($passwordHasher->hashPassword($user, 'password')); | ||||
|  | ||||
|         $em->persist($user); | ||||
|         $em->flush(); | ||||
|  | ||||
|         self::ensureKernelShutdown(); | ||||
|  | ||||
|         yield [$user->getId(), $user->getUsername()]; | ||||
|     } | ||||
|  | ||||
|     public function testList() | ||||
|     { | ||||
|         $client = $this->getClientAuthenticatedAsAdmin(); | ||||
| @@ -135,6 +116,25 @@ final class UserControllerTest extends WebTestCase | ||||
|         $this->isPasswordValid($username, $newPassword); | ||||
|     } | ||||
|  | ||||
|     public static function dataGenerateUserId() | ||||
|     { | ||||
|         self::bootKernel(); | ||||
|         $em = self::getContainer()->get(EntityManagerInterface::class); | ||||
|         /** @var UserPasswordHasherInterface::class $passwordHasher */ | ||||
|         $passwordHasher = self::getContainer()->get(UserPasswordHasherInterface::class); | ||||
|  | ||||
|         $user = new User(); | ||||
|         $user->setUsername('Test_user '.uniqid()); | ||||
|         $user->setPassword($passwordHasher->hashPassword($user, 'password')); | ||||
|  | ||||
|         $em->persist($user); | ||||
|         $em->flush(); | ||||
|  | ||||
|         self::ensureKernelShutdown(); | ||||
|  | ||||
|         yield [$user->getId(), $user->getUsername()]; | ||||
|     } | ||||
|  | ||||
|     protected function isPasswordValid($username, $password) | ||||
|     { | ||||
|         /** @var \Symfony\Component\PasswordHasher\Hasher\UserPasswordHasher $passwordEncoder */ | ||||
|   | ||||
| @@ -31,6 +31,22 @@ final class AgeTest extends KernelTestCase | ||||
|         $this->entityManager = self::getContainer()->get(EntityManagerInterface::class); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider generateQueries | ||||
|      */ | ||||
|     public function testWorking(string $dql, array $args) | ||||
|     { | ||||
|         $dql = $this->entityManager->createQuery($dql)->setMaxResults(3); | ||||
|  | ||||
|         foreach ($args as $key => $value) { | ||||
|             $dql->setParameter($key, $value); | ||||
|         } | ||||
|  | ||||
|         $results = $dql->getResult(); | ||||
|  | ||||
|         $this->assertIsArray($results); | ||||
|     } | ||||
|  | ||||
|     public static function generateQueries(): iterable | ||||
|     { | ||||
|         yield [ | ||||
| @@ -60,20 +76,4 @@ final class AgeTest extends KernelTestCase | ||||
|             ], | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider generateQueries | ||||
|      */ | ||||
|     public function testWorking(string $dql, array $args) | ||||
|     { | ||||
|         $dql = $this->entityManager->createQuery($dql)->setMaxResults(3); | ||||
|  | ||||
|         foreach ($args as $key => $value) { | ||||
|             $dql->setParameter($key, $value); | ||||
|         } | ||||
|  | ||||
|         $results = $dql->getResult(); | ||||
|  | ||||
|         $this->assertIsArray($results); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -31,13 +31,6 @@ final class JsonExtractTest extends KernelTestCase | ||||
|         $this->em = self::getContainer()->get(EntityManagerInterface::class); | ||||
|     } | ||||
|  | ||||
|     public static function dataGenerateDql(): iterable | ||||
|     { | ||||
|         yield ['SELECT JSON_EXTRACT(c.name, \'fr\') FROM '.Country::class.' c', []]; | ||||
|  | ||||
|         yield ['SELECT JSON_EXTRACT(c.name, :lang) FROM '.Country::class.' c', ['lang' => 'fr']]; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider dataGenerateDql | ||||
|      */ | ||||
| @@ -50,4 +43,11 @@ final class JsonExtractTest extends KernelTestCase | ||||
|  | ||||
|         $this->assertIsArray($results, 'simply test that the query return a result'); | ||||
|     } | ||||
|  | ||||
|     public static function dataGenerateDql(): iterable | ||||
|     { | ||||
|         yield ['SELECT JSON_EXTRACT(c.name, \'fr\') FROM '.Country::class.' c', []]; | ||||
|  | ||||
|         yield ['SELECT JSON_EXTRACT(c.name, :lang) FROM '.Country::class.' c', ['lang' => 'fr']]; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -44,26 +44,6 @@ final class NotificationTest extends KernelTestCase | ||||
|         $em->flush(); | ||||
|     } | ||||
|  | ||||
|     public static function generateNotificationData() | ||||
|     { | ||||
|         self::bootKernel(); | ||||
|         $userRepository = self::getContainer()->get(UserRepository::class); | ||||
|  | ||||
|         $senderId = $userRepository | ||||
|             ->findOneBy(['username' => 'center b_social']) | ||||
|             ->getId(); | ||||
|  | ||||
|         $addressesIds = []; | ||||
|         $addressesIds[] = $userRepository | ||||
|             ->findOneBy(['username' => 'center b_direction']) | ||||
|             ->getId(); | ||||
|  | ||||
|         yield [ | ||||
|             $senderId, | ||||
|             $addressesIds, | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|     public function testAddAddresseeStoreAnUread() | ||||
|     { | ||||
|         $notification = new Notification(); | ||||
| @@ -139,4 +119,24 @@ final class NotificationTest extends KernelTestCase | ||||
|             $this->assertContains($addresseeId, $unreadIds); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public static function generateNotificationData() | ||||
|     { | ||||
|         self::bootKernel(); | ||||
|         $userRepository = self::getContainer()->get(UserRepository::class); | ||||
|  | ||||
|         $senderId = $userRepository | ||||
|             ->findOneBy(['username' => 'center b_social']) | ||||
|             ->getId(); | ||||
|  | ||||
|         $addressesIds = []; | ||||
|         $addressesIds[] = $userRepository | ||||
|             ->findOneBy(['username' => 'center b_direction']) | ||||
|             ->getId(); | ||||
|  | ||||
|         yield [ | ||||
|             $senderId, | ||||
|             $addressesIds, | ||||
|         ]; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -33,6 +33,23 @@ final class PageTest extends KernelTestCase | ||||
|         $this->prophet = new \Prophecy\Prophet(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param int $number | ||||
|      * @param int $itemPerPage | ||||
|      * @param int $expectedItemPerPage | ||||
|      * | ||||
|      * @dataProvider generateGetFirstItemNumber | ||||
|      */ | ||||
|     public function testGetFirstItemNumber( | ||||
|         $number, | ||||
|         $itemPerPage, | ||||
|         $expectedItemPerPage, | ||||
|     ) { | ||||
|         $page = $this->generatePage($number, $itemPerPage); | ||||
|  | ||||
|         $this->assertEquals($expectedItemPerPage, $page->getFirstItemNumber()); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * return a set of element to testGetFirstItemNumber. | ||||
|      * | ||||
| @@ -51,6 +68,23 @@ final class PageTest extends KernelTestCase | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param int $number | ||||
|      * @param int $itemPerPage | ||||
|      * @param int $expectedItemPerPage | ||||
|      * | ||||
|      * @dataProvider generateGetLastItemNumber | ||||
|      */ | ||||
|     public function testGetLastItemNumber( | ||||
|         $number, | ||||
|         $itemPerPage, | ||||
|         $expectedItemPerPage, | ||||
|     ) { | ||||
|         $page = $this->generatePage($number, $itemPerPage); | ||||
|  | ||||
|         $this->assertEquals($expectedItemPerPage, $page->getLastItemNumber()); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * return a set of element to testGetLastItemNumber. | ||||
|      * | ||||
| @@ -69,40 +103,6 @@ final class PageTest extends KernelTestCase | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param int $number | ||||
|      * @param int $itemPerPage | ||||
|      * @param int $expectedItemPerPage | ||||
|      * | ||||
|      * @dataProvider generateGetFirstItemNumber | ||||
|      */ | ||||
|     public function testGetFirstItemNumber( | ||||
|         $number, | ||||
|         $itemPerPage, | ||||
|         $expectedItemPerPage, | ||||
|     ) { | ||||
|         $page = $this->generatePage($number, $itemPerPage); | ||||
|  | ||||
|         $this->assertEquals($expectedItemPerPage, $page->getFirstItemNumber()); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param int $number | ||||
|      * @param int $itemPerPage | ||||
|      * @param int $expectedItemPerPage | ||||
|      * | ||||
|      * @dataProvider generateGetLastItemNumber | ||||
|      */ | ||||
|     public function testGetLastItemNumber( | ||||
|         $number, | ||||
|         $itemPerPage, | ||||
|         $expectedItemPerPage, | ||||
|     ) { | ||||
|         $page = $this->generatePage($number, $itemPerPage); | ||||
|  | ||||
|         $this->assertEquals($expectedItemPerPage, $page->getLastItemNumber()); | ||||
|     } | ||||
|  | ||||
|     public function testPageNumber() | ||||
|     { | ||||
|         $page = $this->generatePage(1); | ||||
|   | ||||
| @@ -34,73 +34,6 @@ final class PaginatorTest extends KernelTestCase | ||||
|         $this->prophet = new \Prophecy\Prophet(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * generate an array with a set of page with : | ||||
|      * - total items ; | ||||
|      * - item per page ; | ||||
|      * - current page number ; | ||||
|      * - expected hasNextPage result. | ||||
|      * | ||||
|      * @return array | ||||
|      */ | ||||
|     public static function generateHasNextPage() | ||||
|     { | ||||
|         return [ | ||||
|             [10, 10, 1, false], | ||||
|             [20, 10, 1, true], | ||||
|             [12, 10, 1, true], | ||||
|             [12, 10, 2, false], | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|     public static function generateHasPage() | ||||
|     { | ||||
|         return [ | ||||
|             [10, 10, -1, false], | ||||
|             [12, 10, 1,  true], | ||||
|             [12, 10, 2,  true], | ||||
|             [12, 10, 3,  false], | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * generate an array with a set of page with : | ||||
|      * - total items ; | ||||
|      * - item per page ; | ||||
|      * - current page number ; | ||||
|      * - expected hasPreviousPage result. | ||||
|      * | ||||
|      * @return array | ||||
|      */ | ||||
|     public static function generateHasPreviousPage() | ||||
|     { | ||||
|         return [ | ||||
|             [10, 10, 1, false], | ||||
|             [20, 10, 1, false], | ||||
|             [12, 10, 1, false], | ||||
|             [12, 10, 2, true], | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * generate a set of pages with different maxItem, itemPerPage, and | ||||
|      * expected page number. | ||||
|      * | ||||
|      * @return array | ||||
|      */ | ||||
|     public static function generatePageNumber() | ||||
|     { | ||||
|         return [ | ||||
|             [12, 10, 2], | ||||
|             [20, 10, 2], | ||||
|             [21, 10, 3], | ||||
|             [19, 10, 2], | ||||
|             [1, 10, 1], | ||||
|             [0, 10, 1], | ||||
|             [10, 10, 1], | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|     public function testGetPage() | ||||
|     { | ||||
|         $paginator = $this->generatePaginator(105, 10); | ||||
| @@ -127,6 +60,25 @@ final class PaginatorTest extends KernelTestCase | ||||
|         $this->assertEquals($expectedHasNextPage, $paginator->hasNextPage()); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * generate an array with a set of page with : | ||||
|      * - total items ; | ||||
|      * - item per page ; | ||||
|      * - current page number ; | ||||
|      * - expected hasNextPage result. | ||||
|      * | ||||
|      * @return array | ||||
|      */ | ||||
|     public static function generateHasNextPage() | ||||
|     { | ||||
|         return [ | ||||
|             [10, 10, 1, false], | ||||
|             [20, 10, 1, true], | ||||
|             [12, 10, 1, true], | ||||
|             [12, 10, 2, false], | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * test the HasPage function. | ||||
|      * | ||||
| @@ -148,6 +100,16 @@ final class PaginatorTest extends KernelTestCase | ||||
|         $this->assertEquals($expectedHasPage, $paginator->hasPage($pageNumber)); | ||||
|     } | ||||
|  | ||||
|     public static function generateHasPage() | ||||
|     { | ||||
|         return [ | ||||
|             [10, 10, -1, false], | ||||
|             [12, 10, 1,  true], | ||||
|             [12, 10, 2,  true], | ||||
|             [12, 10, 3,  false], | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param int $totalItems | ||||
|      * @param int $itemPerPage | ||||
| @@ -166,6 +128,25 @@ final class PaginatorTest extends KernelTestCase | ||||
|         $this->assertEquals($expectedHasNextPage, $paginator->hasPreviousPage()); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * generate an array with a set of page with : | ||||
|      * - total items ; | ||||
|      * - item per page ; | ||||
|      * - current page number ; | ||||
|      * - expected hasPreviousPage result. | ||||
|      * | ||||
|      * @return array | ||||
|      */ | ||||
|     public static function generateHasPreviousPage() | ||||
|     { | ||||
|         return [ | ||||
|             [10, 10, 1, false], | ||||
|             [20, 10, 1, false], | ||||
|             [12, 10, 1, false], | ||||
|             [12, 10, 2, true], | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Test that the countPages method (and his alias `count`) return | ||||
|      * valid results. | ||||
| @@ -184,6 +165,25 @@ final class PaginatorTest extends KernelTestCase | ||||
|         $this->assertEquals($expectedPageNumber, \count($paginator)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * generate a set of pages with different maxItem, itemPerPage, and | ||||
|      * expected page number. | ||||
|      * | ||||
|      * @return array | ||||
|      */ | ||||
|     public static function generatePageNumber() | ||||
|     { | ||||
|         return [ | ||||
|             [12, 10, 2], | ||||
|             [20, 10, 2], | ||||
|             [21, 10, 3], | ||||
|             [19, 10, 2], | ||||
|             [1, 10, 1], | ||||
|             [0, 10, 1], | ||||
|             [10, 10, 1], | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|     public function testPagesGenerator() | ||||
|     { | ||||
|         $paginator = $this->generatePaginator(105, 10); | ||||
|   | ||||
| @@ -25,6 +25,25 @@ use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag; | ||||
|  */ | ||||
| final class PhonenumberHelperTest extends KernelTestCase | ||||
| { | ||||
|     /** | ||||
|      * @dataProvider formatPhonenumbers | ||||
|      */ | ||||
|     public function testFormatPhonenumbers(string $defaultCarrierCode, string $phoneNumber, string $expected) | ||||
|     { | ||||
|         $util = PhoneNumberUtil::getInstance(); | ||||
|         $subject = new PhonenumberHelper( | ||||
|             new ArrayAdapter(), | ||||
|             new ParameterBag([ | ||||
|                 'chill_main.phone_helper' => [ | ||||
|                     'default_carrier_code' => $defaultCarrierCode, | ||||
|                 ], | ||||
|             ]), | ||||
|             new NullLogger() | ||||
|         ); | ||||
|  | ||||
|         $this->assertEquals($expected, $subject->format($util->parse($phoneNumber))); | ||||
|     } | ||||
|  | ||||
|     public static function formatPhonenumbers() | ||||
|     { | ||||
|         yield [ | ||||
| @@ -51,23 +70,4 @@ final class PhonenumberHelperTest extends KernelTestCase | ||||
|             '00 33 6 23 12 45 54', | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider formatPhonenumbers | ||||
|      */ | ||||
|     public function testFormatPhonenumbers(string $defaultCarrierCode, string $phoneNumber, string $expected) | ||||
|     { | ||||
|         $util = PhoneNumberUtil::getInstance(); | ||||
|         $subject = new PhonenumberHelper( | ||||
|             new ArrayAdapter(), | ||||
|             new ParameterBag([ | ||||
|                 'chill_main.phone_helper' => [ | ||||
|                     'default_carrier_code' => $defaultCarrierCode, | ||||
|                 ], | ||||
|             ]), | ||||
|             new NullLogger() | ||||
|         ); | ||||
|  | ||||
|         $this->assertEquals($expected, $subject->format($util->parse($phoneNumber))); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -21,23 +21,6 @@ use PHPUnit\Framework\TestCase; | ||||
|  */ | ||||
| final class ExtractDateFromPatternTest extends TestCase | ||||
| { | ||||
|     public static function provideSubjects() | ||||
|     { | ||||
|         yield ['15/06/1981', '', 1, '1981-06-15']; | ||||
|  | ||||
|         yield ['15/06/1981 30/12/1987', '', 2, '1981-06-15', '1987-12-30']; | ||||
|  | ||||
|         yield ['diallo 15/06/1981', 'diallo', 1, '1981-06-15']; | ||||
|  | ||||
|         yield ['diallo  31/03/1981', 'diallo', 1, '1981-03-31']; | ||||
|  | ||||
|         yield ['diallo 15-06-1981', 'diallo', 1, '1981-06-15']; | ||||
|  | ||||
|         yield ['diallo 1981-12-08', 'diallo', 1, '1981-12-08']; | ||||
|  | ||||
|         yield ['diallo', 'diallo', 0]; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider provideSubjects | ||||
|      */ | ||||
| @@ -59,4 +42,21 @@ final class ExtractDateFromPatternTest extends TestCase | ||||
|             $this->assertContains($date, $dates); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public static function provideSubjects() | ||||
|     { | ||||
|         yield ['15/06/1981', '', 1, '1981-06-15']; | ||||
|  | ||||
|         yield ['15/06/1981 30/12/1987', '', 2, '1981-06-15', '1987-12-30']; | ||||
|  | ||||
|         yield ['diallo 15/06/1981', 'diallo', 1, '1981-06-15']; | ||||
|  | ||||
|         yield ['diallo  31/03/1981', 'diallo', 1, '1981-03-31']; | ||||
|  | ||||
|         yield ['diallo 15-06-1981', 'diallo', 1, '1981-06-15']; | ||||
|  | ||||
|         yield ['diallo 1981-12-08', 'diallo', 1, '1981-12-08']; | ||||
|  | ||||
|         yield ['diallo', 'diallo', 0]; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -22,6 +22,21 @@ use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag; | ||||
|  */ | ||||
| final class ExtractPhonenumberFromPatternTest extends KernelTestCase | ||||
| { | ||||
|     /** | ||||
|      * @dataProvider provideData | ||||
|      */ | ||||
|     public function testExtract(string $defaultCarrierCode, mixed $subject, mixed $expectedCount, mixed $expected, mixed $filteredSubject, mixed $msg) | ||||
|     { | ||||
|         $extractor = new ExtractPhonenumberFromPattern(new ParameterBag(['chill_main' => [ | ||||
|             'phone_helper' => ['default_carrier_code' => $defaultCarrierCode], | ||||
|         ]])); | ||||
|         $result = $extractor->extractPhonenumber($subject); | ||||
|  | ||||
|         $this->assertCount($expectedCount, $result->getFound()); | ||||
|         $this->assertEquals($filteredSubject, $result->getFilteredSubject()); | ||||
|         $this->assertEquals($expected, $result->getFound()); | ||||
|     } | ||||
|  | ||||
|     public static function provideData() | ||||
|     { | ||||
|         yield ['BE', 'Diallo', 0, [], 'Diallo', 'no phonenumber']; | ||||
| @@ -44,19 +59,4 @@ final class ExtractPhonenumberFromPatternTest extends KernelTestCase | ||||
|  | ||||
|         yield ['FR', 'Diallo +32486 123 456', 1, ['+32486123456'], 'Diallo', 'a phonenumber and a name']; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider provideData | ||||
|      */ | ||||
|     public function testExtract(string $defaultCarrierCode, mixed $subject, mixed $expectedCount, mixed $expected, mixed $filteredSubject, mixed $msg) | ||||
|     { | ||||
|         $extractor = new ExtractPhonenumberFromPattern(new ParameterBag(['chill_main' => [ | ||||
|             'phone_helper' => ['default_carrier_code' => $defaultCarrierCode], | ||||
|         ]])); | ||||
|         $result = $extractor->extractPhonenumber($subject); | ||||
|  | ||||
|         $this->assertCount($expectedCount, $result->getFound()); | ||||
|         $this->assertEquals($filteredSubject, $result->getFilteredSubject()); | ||||
|         $this->assertEquals($expected, $result->getFound()); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -45,6 +45,29 @@ final class AuthorizationHelperTest extends KernelTestCase | ||||
|         self::bootKernel(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @group legacy | ||||
|      */ | ||||
|     public function testGetParentRoles() | ||||
|     { | ||||
|         $parentRoles = $this->getAuthorizationHelper() | ||||
|             ->getParentRoles('CHILL_INHERITED_ROLE_1'); | ||||
|  | ||||
|         $this->assertContains( | ||||
|             'CHILL_MASTER_ROLE', | ||||
|             $parentRoles, | ||||
|             'Assert that `CHILL_MASTER_ROLE` is a parent of `CHILL_INHERITED_ROLE_1`' | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider dataProvider_getReachableCenters | ||||
|      */ | ||||
|     public function testGetReachableCenters(mixed $test, mixed $result, mixed $msg) | ||||
|     { | ||||
|         $this->assertEquals($test, $result, $msg); | ||||
|     } | ||||
|  | ||||
|     public static function dataProvider_getReachableCenters() | ||||
|     { | ||||
|         self::bootKernel(); | ||||
| @@ -143,6 +166,30 @@ final class AuthorizationHelperTest extends KernelTestCase | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider dataProvider_getReachableScopes | ||||
|      * | ||||
|      * @param bool   $expectedResult | ||||
|      * @param string $message | ||||
|      */ | ||||
|     public function testGetReachableScopes( | ||||
|         $expectedResult, | ||||
|         Scope $testedScope, | ||||
|         User $user, | ||||
|         string $role, | ||||
|         Center $center, | ||||
|         $message, | ||||
|     ) { | ||||
|         $reachableScopes = $this->getAuthorizationHelper() | ||||
|             ->getReachableScopes($user, $role, $center); | ||||
|  | ||||
|         $this->assertEquals( | ||||
|             $expectedResult, | ||||
|             \in_array($testedScope, $reachableScopes, true), | ||||
|             $message | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     public static function dataProvider_getReachableScopes() | ||||
|     { | ||||
|         $centerA = self::prepareCenter(1, 'center A'); | ||||
| @@ -198,53 +245,6 @@ final class AuthorizationHelperTest extends KernelTestCase | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @group legacy | ||||
|      */ | ||||
|     public function testGetParentRoles() | ||||
|     { | ||||
|         $parentRoles = $this->getAuthorizationHelper() | ||||
|             ->getParentRoles('CHILL_INHERITED_ROLE_1'); | ||||
|  | ||||
|         $this->assertContains( | ||||
|             'CHILL_MASTER_ROLE', | ||||
|             $parentRoles, | ||||
|             'Assert that `CHILL_MASTER_ROLE` is a parent of `CHILL_INHERITED_ROLE_1`' | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider dataProvider_getReachableCenters | ||||
|      */ | ||||
|     public function testGetReachableCenters(mixed $test, mixed $result, mixed $msg) | ||||
|     { | ||||
|         $this->assertEquals($test, $result, $msg); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider dataProvider_getReachableScopes | ||||
|      * | ||||
|      * @param bool   $expectedResult | ||||
|      * @param string $message | ||||
|      */ | ||||
|     public function testGetReachableScopes( | ||||
|         $expectedResult, | ||||
|         Scope $testedScope, | ||||
|         User $user, | ||||
|         string $role, | ||||
|         Center $center, | ||||
|         $message, | ||||
|     ) { | ||||
|         $reachableScopes = $this->getAuthorizationHelper() | ||||
|             ->getReachableScopes($user, $role, $center); | ||||
|  | ||||
|         $this->assertEquals( | ||||
|             $expectedResult, | ||||
|             \in_array($testedScope, $reachableScopes, true), | ||||
|             $message | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     public function testtestUserHasAccessUserShouldHaveAccessEntityWithScope() | ||||
|     { | ||||
|         $center = $this->prepareCenter(1, 'center'); | ||||
|   | ||||
| @@ -32,6 +32,14 @@ final class DateNormalizerTest extends KernelTestCase | ||||
|         $this->prophet = new Prophet(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider generateDataNormalize | ||||
|      */ | ||||
|     public function testNormalize(mixed $expected, mixed $date, mixed $format, mixed $locale, mixed $msg) | ||||
|     { | ||||
|         $this->assertEquals($expected, $this->buildDateNormalizer($locale)->normalize($date, $format, []), $msg); | ||||
|     } | ||||
|  | ||||
|     public static function generateDataNormalize() | ||||
|     { | ||||
|         $datetime = \DateTime::createFromFormat('Y-m-d H:i:sO', '2021-06-05 15:05:01+02:00'); | ||||
| @@ -63,14 +71,6 @@ final class DateNormalizerTest extends KernelTestCase | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider generateDataNormalize | ||||
|      */ | ||||
|     public function testNormalize(mixed $expected, mixed $date, mixed $format, mixed $locale, mixed $msg) | ||||
|     { | ||||
|         $this->assertEquals($expected, $this->buildDateNormalizer($locale)->normalize($date, $format, []), $msg); | ||||
|     } | ||||
|  | ||||
|     public function testSupports() | ||||
|     { | ||||
|         $this->assertTrue($this->buildDateNormalizer()->supportsNormalization(new \DateTime(), 'json')); | ||||
|   | ||||
| @@ -35,6 +35,17 @@ final class DoctrineExistingEntityNormalizerTest extends KernelTestCase | ||||
|         $this->normalizer = new DoctrineExistingEntityNormalizer($em, $serializerFactory); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider dataProviderUserId | ||||
|      */ | ||||
|     public function testGetMappedClass(mixed $userId) | ||||
|     { | ||||
|         $data = ['type' => 'user', 'id' => $userId]; | ||||
|         $supports = $this->normalizer->supportsDenormalization($data, User::class); | ||||
|  | ||||
|         $this->assertTrue($supports); | ||||
|     } | ||||
|  | ||||
|     public static function dataProviderUserId() | ||||
|     { | ||||
|         self::bootKernel(); | ||||
| @@ -49,15 +60,4 @@ final class DoctrineExistingEntityNormalizerTest extends KernelTestCase | ||||
|  | ||||
|         yield [$userIds[0]['id']]; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider dataProviderUserId | ||||
|      */ | ||||
|     public function testGetMappedClass(mixed $userId) | ||||
|     { | ||||
|         $data = ['type' => 'user', 'id' => $userId]; | ||||
|         $supports = $this->normalizer->supportsDenormalization($data, User::class); | ||||
|  | ||||
|         $this->assertTrue($supports); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -28,15 +28,6 @@ final class PhonenumberNormalizerTest extends TestCase | ||||
| { | ||||
|     use ProphecyTrait; | ||||
|  | ||||
|     public static function dataProviderNormalizePhonenumber() | ||||
|     { | ||||
|         $phonenumberUtil = PhoneNumberUtil::getInstance(); | ||||
|  | ||||
|         yield [$phonenumberUtil->parse('+32486123465'), 'docgen', ['docgen:expects' => PhoneNumber::class], '0486 12 34 65']; | ||||
|  | ||||
|         yield [null, 'docgen', ['docgen:expects' => PhoneNumber::class], '']; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider dataProviderNormalizePhonenumber | ||||
|      */ | ||||
| @@ -48,4 +39,13 @@ final class PhonenumberNormalizerTest extends TestCase | ||||
|  | ||||
|         $this->assertEquals($expected, $normalizer->normalize($phonenumber, $format, $context)); | ||||
|     } | ||||
|  | ||||
|     public static function dataProviderNormalizePhonenumber() | ||||
|     { | ||||
|         $phonenumberUtil = PhoneNumberUtil::getInstance(); | ||||
|  | ||||
|         yield [$phonenumberUtil->parse('+32486123465'), 'docgen', ['docgen:expects' => PhoneNumber::class], '0486 12 34 65']; | ||||
|  | ||||
|         yield [null, 'docgen', ['docgen:expects' => PhoneNumber::class], '']; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -38,6 +38,34 @@ final class UserNormalizerTest extends TestCase | ||||
| { | ||||
|     use ProphecyTrait; | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider dataProviderUserNormalizer | ||||
|      * | ||||
|      * @throws ExceptionInterface | ||||
|      */ | ||||
|     public function testNormalize(?User $user, mixed $format, mixed $context, mixed $expected) | ||||
|     { | ||||
|         $userRender = $this->prophesize(UserRender::class); | ||||
|         $userRender->renderString(Argument::type(User::class), Argument::type('array'))->willReturn($user ? $user->getLabel() : ''); | ||||
|  | ||||
|         $clock = new MockClock(new \DateTimeImmutable('now')); | ||||
|  | ||||
|         $normalizer = new UserNormalizer($userRender->reveal(), $clock); | ||||
|         $normalizer->setNormalizer(new class () implements NormalizerInterface { | ||||
|             public function normalize($object, ?string $format = null, array $context = []) | ||||
|             { | ||||
|                 return ['context' => $context['docgen:expects'] ?? null]; | ||||
|             } | ||||
|  | ||||
|             public function supportsNormalization($data, ?string $format = null) | ||||
|             { | ||||
|                 return true; | ||||
|             } | ||||
|         }); | ||||
|  | ||||
|         $this->assertEquals($expected, $normalizer->normalize($user, $format, $context)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @throws NumberParseException | ||||
|      */ | ||||
| @@ -112,32 +140,4 @@ final class UserNormalizerTest extends TestCase | ||||
|             'main_center' => ['context' => Center::class], | ||||
|         ]]; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider dataProviderUserNormalizer | ||||
|      * | ||||
|      * @throws ExceptionInterface | ||||
|      */ | ||||
|     public function testNormalize(?User $user, mixed $format, mixed $context, mixed $expected) | ||||
|     { | ||||
|         $userRender = $this->prophesize(UserRender::class); | ||||
|         $userRender->renderString(Argument::type(User::class), Argument::type('array'))->willReturn($user ? $user->getLabel() : ''); | ||||
|  | ||||
|         $clock = new MockClock(new \DateTimeImmutable('now')); | ||||
|  | ||||
|         $normalizer = new UserNormalizer($userRender->reveal(), $clock); | ||||
|         $normalizer->setNormalizer(new class () implements NormalizerInterface { | ||||
|             public function normalize($object, ?string $format = null, array $context = []) | ||||
|             { | ||||
|                 return ['context' => $context['docgen:expects'] ?? null]; | ||||
|             } | ||||
|  | ||||
|             public function supportsNormalization($data, ?string $format = null) | ||||
|             { | ||||
|                 return true; | ||||
|             } | ||||
|         }); | ||||
|  | ||||
|         $this->assertEquals($expected, $normalizer->normalize($user, $format, $context)); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -45,6 +45,14 @@ class CollateAddressWithReferenceOrPostalCodeCronJobTest extends TestCase | ||||
|         self::assertEquals($expected, $job->canRun($execution)); | ||||
|     } | ||||
|  | ||||
|     public static function provideDataCanRun(): iterable | ||||
|     { | ||||
|         yield [new \DateTimeImmutable('2023-07-10T12:00:00'), new \DateTimeImmutable('2023-07-10T11:00:00'), false]; | ||||
|         yield [new \DateTimeImmutable('2023-07-10T12:00:00'), new \DateTimeImmutable('2023-07-10T05:00:00'), true]; | ||||
|         yield [new \DateTimeImmutable('2023-07-10T12:00:00'), new \DateTimeImmutable('2023-07-01T12:00:00'), true]; | ||||
|         yield [new \DateTimeImmutable('2023-07-10T12:00:00'), null, true]; | ||||
|     } | ||||
|  | ||||
|     public function testRun(): void | ||||
|     { | ||||
|         $clock = new MockClock(); | ||||
| @@ -57,12 +65,4 @@ class CollateAddressWithReferenceOrPostalCodeCronJobTest extends TestCase | ||||
|         $actual = $job->run(['last-max-id' => 0]); | ||||
|         self::assertEquals(['last-max-id' => 1], $actual); | ||||
|     } | ||||
|  | ||||
|     public static function provideDataCanRun(): iterable | ||||
|     { | ||||
|         yield [new \DateTimeImmutable('2023-07-10T12:00:00'), new \DateTimeImmutable('2023-07-10T11:00:00'), false]; | ||||
|         yield [new \DateTimeImmutable('2023-07-10T12:00:00'), new \DateTimeImmutable('2023-07-10T05:00:00'), true]; | ||||
|         yield [new \DateTimeImmutable('2023-07-10T12:00:00'), new \DateTimeImmutable('2023-07-01T12:00:00'), true]; | ||||
|         yield [new \DateTimeImmutable('2023-07-10T12:00:00'), null, true]; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -29,37 +29,6 @@ final class RollingDateConverterTest extends TestCase | ||||
|         $this->converter = new RollingDateConverter(); | ||||
|     } | ||||
|  | ||||
|     public static function generateDataConversionDate(): iterable | ||||
|     { | ||||
|         $format = 'Y-m-d His'; | ||||
|  | ||||
|         yield [RollingDate::T_MONTH_CURRENT_START, '2022-11-01 000000', $format]; | ||||
|  | ||||
|         yield [RollingDate::T_MONTH_NEXT_START, '2022-12-01 000000', $format]; | ||||
|  | ||||
|         yield [RollingDate::T_MONTH_PREVIOUS_START, '2022-10-01 000000', $format]; | ||||
|  | ||||
|         yield [RollingDate::T_QUARTER_CURRENT_START, '2022-10-01 000000', $format]; | ||||
|  | ||||
|         yield [RollingDate::T_QUARTER_NEXT_START, '2023-01-01 000000', $format]; | ||||
|  | ||||
|         yield [RollingDate::T_QUARTER_PREVIOUS_START, '2022-07-01 000000', $format]; | ||||
|  | ||||
|         yield [RollingDate::T_TODAY, '2022-11-07 000000', $format]; | ||||
|  | ||||
|         yield [RollingDate::T_WEEK_CURRENT_START, '2022-11-07 000000', $format]; | ||||
|  | ||||
|         yield [RollingDate::T_WEEK_NEXT_START, '2022-11-14 000000', $format]; | ||||
|  | ||||
|         yield [RollingDate::T_WEEK_PREVIOUS_START, '2022-10-31 000000', $format]; | ||||
|  | ||||
|         yield [RollingDate::T_YEAR_CURRENT_START, '2022-01-01 000000', $format]; | ||||
|  | ||||
|         yield [RollingDate::T_YEAR_NEXT_START, '2023-01-01 000000', $format]; | ||||
|  | ||||
|         yield [RollingDate::T_YEAR_PREVIOUS_START, '2021-01-01 000000', $format]; | ||||
|     } | ||||
|  | ||||
|     public function testConversionFixedDate() | ||||
|     { | ||||
|         $rollingDate = new RollingDate(RollingDate::T_FIXED_DATE, new \DateTimeImmutable('2022-01-01')); | ||||
| @@ -97,4 +66,35 @@ final class RollingDateConverterTest extends TestCase | ||||
|             $this->converter->convert($rollingDate) | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     public static function generateDataConversionDate(): iterable | ||||
|     { | ||||
|         $format = 'Y-m-d His'; | ||||
|  | ||||
|         yield [RollingDate::T_MONTH_CURRENT_START, '2022-11-01 000000', $format]; | ||||
|  | ||||
|         yield [RollingDate::T_MONTH_NEXT_START, '2022-12-01 000000', $format]; | ||||
|  | ||||
|         yield [RollingDate::T_MONTH_PREVIOUS_START, '2022-10-01 000000', $format]; | ||||
|  | ||||
|         yield [RollingDate::T_QUARTER_CURRENT_START, '2022-10-01 000000', $format]; | ||||
|  | ||||
|         yield [RollingDate::T_QUARTER_NEXT_START, '2023-01-01 000000', $format]; | ||||
|  | ||||
|         yield [RollingDate::T_QUARTER_PREVIOUS_START, '2022-07-01 000000', $format]; | ||||
|  | ||||
|         yield [RollingDate::T_TODAY, '2022-11-07 000000', $format]; | ||||
|  | ||||
|         yield [RollingDate::T_WEEK_CURRENT_START, '2022-11-07 000000', $format]; | ||||
|  | ||||
|         yield [RollingDate::T_WEEK_NEXT_START, '2022-11-14 000000', $format]; | ||||
|  | ||||
|         yield [RollingDate::T_WEEK_PREVIOUS_START, '2022-10-31 000000', $format]; | ||||
|  | ||||
|         yield [RollingDate::T_YEAR_CURRENT_START, '2022-01-01 000000', $format]; | ||||
|  | ||||
|         yield [RollingDate::T_YEAR_NEXT_START, '2023-01-01 000000', $format]; | ||||
|  | ||||
|         yield [RollingDate::T_YEAR_PREVIOUS_START, '2021-01-01 000000', $format]; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -48,6 +48,32 @@ class CancelStaleWorkflowCronJobTest extends TestCase | ||||
|         self::assertEquals($expected, $cronJob->canRun($cronJobExecution)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @throws \Exception | ||||
|      */ | ||||
|     public static function buildTestCanRunData(): iterable | ||||
|     { | ||||
|         yield [ | ||||
|             (new CronJobExecution('last-canceled-workflow-id'))->setLastEnd(new \DateTimeImmutable('2023-12-31 00:00:00', new \DateTimeZone('+00:00'))), | ||||
|             true, | ||||
|         ]; | ||||
|  | ||||
|         yield [ | ||||
|             (new CronJobExecution('last-canceled-workflow-id'))->setLastEnd(new \DateTimeImmutable('2023-12-30 23:59:59', new \DateTimeZone('+00:00'))), | ||||
|             true, | ||||
|         ]; | ||||
|  | ||||
|         yield [ | ||||
|             (new CronJobExecution('last-canceled-workflow-id'))->setLastEnd(new \DateTimeImmutable('2023-12-31 00:00:01', new \DateTimeZone('+00:00'))), | ||||
|             false, | ||||
|         ]; | ||||
|  | ||||
|         yield [ | ||||
|             null, | ||||
|             true, | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @throws \DateMalformedStringException | ||||
|      * @throws \DateInvalidTimeZoneException | ||||
| @@ -85,32 +111,6 @@ class CancelStaleWorkflowCronJobTest extends TestCase | ||||
|         return $entityWorkflow; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @throws \Exception | ||||
|      */ | ||||
|     public static function buildTestCanRunData(): iterable | ||||
|     { | ||||
|         yield [ | ||||
|             (new CronJobExecution('last-canceled-workflow-id'))->setLastEnd(new \DateTimeImmutable('2023-12-31 00:00:00', new \DateTimeZone('+00:00'))), | ||||
|             true, | ||||
|         ]; | ||||
|  | ||||
|         yield [ | ||||
|             (new CronJobExecution('last-canceled-workflow-id'))->setLastEnd(new \DateTimeImmutable('2023-12-30 23:59:59', new \DateTimeZone('+00:00'))), | ||||
|             true, | ||||
|         ]; | ||||
|  | ||||
|         yield [ | ||||
|             (new CronJobExecution('last-canceled-workflow-id'))->setLastEnd(new \DateTimeImmutable('2023-12-31 00:00:01', new \DateTimeZone('+00:00'))), | ||||
|             false, | ||||
|         ]; | ||||
|  | ||||
|         yield [ | ||||
|             null, | ||||
|             true, | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|     private function buildMessageBus(bool $expectDispatchAtLeastOnce = false): MessageBusInterface | ||||
|     { | ||||
|         $messageBus = $this->createMock(MessageBusInterface::class); | ||||
|   | ||||
| @@ -30,84 +30,16 @@ final class AddressRenderTest extends KernelTestCase | ||||
|         self::bootKernel(); | ||||
|     } | ||||
|  | ||||
|     public static function addressDataProviderBEWithBuilding(): \Iterator | ||||
|     /** | ||||
|      * @dataProvider complexAddressDataProviderBE | ||||
|      */ | ||||
|     public function testRenderComplexAddressBE(Address $addr, string $expectedString): void | ||||
|     { | ||||
|         $addr = new Address(); | ||||
|         $country = (new Country()) | ||||
|             ->setName(['fr' => 'Belgium']) | ||||
|             ->setCountryCode('BE'); | ||||
|         $postCode = new PostalCode(); | ||||
|         $postCode->setName('Locality') | ||||
|             ->setCode('012345') | ||||
|             ->setCountry($country); | ||||
|         $engine = self::getContainer()->get(\Twig\Environment::class); | ||||
|         $translatableStringHelper = self::getContainer()->get(TranslatableStringHelper::class); | ||||
|         $renderer = new AddressRender($engine, $translatableStringHelper); | ||||
|  | ||||
|         $addr->setStreet('Rue ABC') | ||||
|             ->setStreetNumber('5') | ||||
|             ->setPostcode($postCode); | ||||
|  | ||||
|         $addr->setBuildingName('Résidence "Les Bleuets"'); | ||||
|  | ||||
|         yield [$addr, 'Résidence "Les Bleuets" — Rue ABC, 5 — 012345 Locality — Belgium']; | ||||
|     } | ||||
|  | ||||
|     public static function addressDataProviderBEWithSteps(): \Iterator | ||||
|     { | ||||
|         $addr = new Address(); | ||||
|         $country = (new Country()) | ||||
|             ->setName(['fr' => 'Belgium']) | ||||
|             ->setCountryCode('BE'); | ||||
|         $postCode = new PostalCode(); | ||||
|         $postCode->setName('Locality') | ||||
|             ->setCode('012345') | ||||
|             ->setCountry($country); | ||||
|  | ||||
|         $addr->setStreet('Rue ABC') | ||||
|             ->setStreetNumber('5') | ||||
|             ->setPostcode($postCode); | ||||
|  | ||||
|         $addr->setSteps('4'); | ||||
|  | ||||
|         yield [$addr, 'esc 4 — Rue ABC, 5 — 012345 Locality — Belgium']; | ||||
|     } | ||||
|  | ||||
|     public static function addressDataProviderFRWithBuilding(): \Iterator | ||||
|     { | ||||
|         $addr = new Address(); | ||||
|         $country = (new Country()) | ||||
|             ->setName(['fr' => 'France']) | ||||
|             ->setCountryCode('FR'); | ||||
|         $postCode = new PostalCode(); | ||||
|         $postCode->setName('Locality') | ||||
|             ->setCode('012345') | ||||
|             ->setCountry($country); | ||||
|  | ||||
|         $addr->setStreet('Rue ABC') | ||||
|             ->setStreetNumber('5') | ||||
|             ->setPostcode($postCode); | ||||
|  | ||||
|         $addr->setBuildingName('Résidence "Les Bleuets"'); | ||||
|  | ||||
|         yield [$addr, 'Résidence "Les Bleuets" — 5, Rue ABC — 012345 Locality — France']; | ||||
|     } | ||||
|  | ||||
|     public static function addressDataProviderFRWithSteps(): \Iterator | ||||
|     { | ||||
|         $addr = new Address(); | ||||
|         $country = (new Country()) | ||||
|             ->setName(['fr' => 'France']) | ||||
|             ->setCountryCode('FR'); | ||||
|         $postCode = new PostalCode(); | ||||
|         $postCode->setName('Locality') | ||||
|             ->setCode('012345') | ||||
|             ->setCountry($country); | ||||
|  | ||||
|         $addr->setStreet('Rue ABC') | ||||
|             ->setStreetNumber('5') | ||||
|             ->setPostcode($postCode); | ||||
|  | ||||
|         $addr->setSteps('4'); | ||||
|  | ||||
|         yield [$addr, 'esc 4 — 5, Rue ABC — 012345 Locality — France']; | ||||
|         $this->assertEquals($expectedString, $renderer->renderString($addr, [])); | ||||
|     } | ||||
|  | ||||
|     public static function complexAddressDataProviderBE(): \Iterator | ||||
| @@ -134,6 +66,18 @@ final class AddressRenderTest extends KernelTestCase | ||||
|         yield [$addr, 'Résidence "Les Bleuets" - appart 1 - ét 2 - coul 3 - esc 4 — Rue ABC, 5 — 012345 Locality — Belgium']; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider complexAddressDataProviderFR | ||||
|      */ | ||||
|     public function testRenderComplexAddressFR(Address $addr, string $expectedString): void | ||||
|     { | ||||
|         $engine = self::getContainer()->get(\Twig\Environment::class); | ||||
|         $translatableStringHelper = self::getContainer()->get(TranslatableStringHelper::class); | ||||
|         $renderer = new AddressRender($engine, $translatableStringHelper); | ||||
|  | ||||
|         $this->assertEquals($expectedString, $renderer->renderString($addr, [])); | ||||
|     } | ||||
|  | ||||
|     public static function complexAddressDataProviderFR(): \Iterator | ||||
|     { | ||||
|         $addr = new Address(); | ||||
| @@ -160,6 +104,18 @@ final class AddressRenderTest extends KernelTestCase | ||||
|         yield [$addr, 'appart 1 - ét 2 - coul 3 - esc 4 — Résidence "Les Bleuets" — 5, Rue ABC — A droite de la porte — 012345 Locality CEDEX — France']; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider noFullAddressDataProviderBE | ||||
|      */ | ||||
|     public function testRenderNoFullAddressBE(Address $addr, string $expectedString): void | ||||
|     { | ||||
|         $engine = self::getContainer()->get(\Twig\Environment::class); | ||||
|         $translatableStringHelper = self::getContainer()->get(TranslatableStringHelper::class); | ||||
|         $renderer = new AddressRender($engine, $translatableStringHelper); | ||||
|  | ||||
|         $this->assertEquals($expectedString, $renderer->renderString($addr, [])); | ||||
|     } | ||||
|  | ||||
|     public static function noFullAddressDataProviderBE(): \Iterator | ||||
|     { | ||||
|         $addr = new Address(); | ||||
| @@ -177,6 +133,18 @@ final class AddressRenderTest extends KernelTestCase | ||||
|         yield [$addr, '012345 Locality — Belgium']; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider simpleAddressDataProviderBE | ||||
|      */ | ||||
|     public function testRenderStringSimpleAddressBE(Address $addr, string $expectedString): void | ||||
|     { | ||||
|         $engine = self::getContainer()->get(\Twig\Environment::class); | ||||
|         $translatableStringHelper = self::getContainer()->get(TranslatableStringHelper::class); | ||||
|         $renderer = new AddressRender($engine, $translatableStringHelper); | ||||
|  | ||||
|         $this->assertEquals($expectedString, $renderer->renderString($addr, [])); | ||||
|     } | ||||
|  | ||||
|     public static function simpleAddressDataProviderBE(): \Iterator | ||||
|     { | ||||
|         $addr = new Address(); | ||||
| @@ -195,6 +163,18 @@ final class AddressRenderTest extends KernelTestCase | ||||
|         yield [$addr, 'Rue ABC, 5 — 012345 Locality — Belgium']; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider simpleAddressDataProviderFR | ||||
|      */ | ||||
|     public function testRenderStringSimpleAddressFR(Address $addr, string $expectedString): void | ||||
|     { | ||||
|         $engine = self::getContainer()->get(\Twig\Environment::class); | ||||
|         $translatableStringHelper = self::getContainer()->get(TranslatableStringHelper::class); | ||||
|         $renderer = new AddressRender($engine, $translatableStringHelper); | ||||
|  | ||||
|         $this->assertEquals($expectedString, $renderer->renderString($addr, [])); | ||||
|     } | ||||
|  | ||||
|     public static function simpleAddressDataProviderFR(): \Iterator | ||||
|     { | ||||
|         $addr = new Address(); | ||||
| @@ -213,66 +193,6 @@ final class AddressRenderTest extends KernelTestCase | ||||
|         yield [$addr, '5, Rue ABC — 012345 Locality — France']; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider complexAddressDataProviderBE | ||||
|      */ | ||||
|     public function testRenderComplexAddressBE(Address $addr, string $expectedString): void | ||||
|     { | ||||
|         $engine = self::getContainer()->get(\Twig\Environment::class); | ||||
|         $translatableStringHelper = self::getContainer()->get(TranslatableStringHelper::class); | ||||
|         $renderer = new AddressRender($engine, $translatableStringHelper); | ||||
|  | ||||
|         $this->assertEquals($expectedString, $renderer->renderString($addr, [])); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider complexAddressDataProviderFR | ||||
|      */ | ||||
|     public function testRenderComplexAddressFR(Address $addr, string $expectedString): void | ||||
|     { | ||||
|         $engine = self::getContainer()->get(\Twig\Environment::class); | ||||
|         $translatableStringHelper = self::getContainer()->get(TranslatableStringHelper::class); | ||||
|         $renderer = new AddressRender($engine, $translatableStringHelper); | ||||
|  | ||||
|         $this->assertEquals($expectedString, $renderer->renderString($addr, [])); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider noFullAddressDataProviderBE | ||||
|      */ | ||||
|     public function testRenderNoFullAddressBE(Address $addr, string $expectedString): void | ||||
|     { | ||||
|         $engine = self::getContainer()->get(\Twig\Environment::class); | ||||
|         $translatableStringHelper = self::getContainer()->get(TranslatableStringHelper::class); | ||||
|         $renderer = new AddressRender($engine, $translatableStringHelper); | ||||
|  | ||||
|         $this->assertEquals($expectedString, $renderer->renderString($addr, [])); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider simpleAddressDataProviderBE | ||||
|      */ | ||||
|     public function testRenderStringSimpleAddressBE(Address $addr, string $expectedString): void | ||||
|     { | ||||
|         $engine = self::getContainer()->get(\Twig\Environment::class); | ||||
|         $translatableStringHelper = self::getContainer()->get(TranslatableStringHelper::class); | ||||
|         $renderer = new AddressRender($engine, $translatableStringHelper); | ||||
|  | ||||
|         $this->assertEquals($expectedString, $renderer->renderString($addr, [])); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider simpleAddressDataProviderFR | ||||
|      */ | ||||
|     public function testRenderStringSimpleAddressFR(Address $addr, string $expectedString): void | ||||
|     { | ||||
|         $engine = self::getContainer()->get(\Twig\Environment::class); | ||||
|         $translatableStringHelper = self::getContainer()->get(TranslatableStringHelper::class); | ||||
|         $renderer = new AddressRender($engine, $translatableStringHelper); | ||||
|  | ||||
|         $this->assertEquals($expectedString, $renderer->renderString($addr, [])); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider addressDataProviderBEWithBuilding | ||||
|      */ | ||||
| @@ -285,6 +205,26 @@ final class AddressRenderTest extends KernelTestCase | ||||
|         $this->assertEquals($expectedString, $renderer->renderString($addr, [])); | ||||
|     } | ||||
|  | ||||
|     public static function addressDataProviderBEWithBuilding(): \Iterator | ||||
|     { | ||||
|         $addr = new Address(); | ||||
|         $country = (new Country()) | ||||
|             ->setName(['fr' => 'Belgium']) | ||||
|             ->setCountryCode('BE'); | ||||
|         $postCode = new PostalCode(); | ||||
|         $postCode->setName('Locality') | ||||
|             ->setCode('012345') | ||||
|             ->setCountry($country); | ||||
|  | ||||
|         $addr->setStreet('Rue ABC') | ||||
|             ->setStreetNumber('5') | ||||
|             ->setPostcode($postCode); | ||||
|  | ||||
|         $addr->setBuildingName('Résidence "Les Bleuets"'); | ||||
|  | ||||
|         yield [$addr, 'Résidence "Les Bleuets" — Rue ABC, 5 — 012345 Locality — Belgium']; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider addressDataProviderFRWithBuilding | ||||
|      */ | ||||
| @@ -297,6 +237,26 @@ final class AddressRenderTest extends KernelTestCase | ||||
|         $this->assertEquals($expectedString, $renderer->renderString($addr, [])); | ||||
|     } | ||||
|  | ||||
|     public static function addressDataProviderFRWithBuilding(): \Iterator | ||||
|     { | ||||
|         $addr = new Address(); | ||||
|         $country = (new Country()) | ||||
|             ->setName(['fr' => 'France']) | ||||
|             ->setCountryCode('FR'); | ||||
|         $postCode = new PostalCode(); | ||||
|         $postCode->setName('Locality') | ||||
|             ->setCode('012345') | ||||
|             ->setCountry($country); | ||||
|  | ||||
|         $addr->setStreet('Rue ABC') | ||||
|             ->setStreetNumber('5') | ||||
|             ->setPostcode($postCode); | ||||
|  | ||||
|         $addr->setBuildingName('Résidence "Les Bleuets"'); | ||||
|  | ||||
|         yield [$addr, 'Résidence "Les Bleuets" — 5, Rue ABC — 012345 Locality — France']; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider addressDataProviderBEWithSteps | ||||
|      */ | ||||
| @@ -309,6 +269,26 @@ final class AddressRenderTest extends KernelTestCase | ||||
|         $this->assertEquals($expectedString, $renderer->renderString($addr, [])); | ||||
|     } | ||||
|  | ||||
|     public static function addressDataProviderBEWithSteps(): \Iterator | ||||
|     { | ||||
|         $addr = new Address(); | ||||
|         $country = (new Country()) | ||||
|             ->setName(['fr' => 'Belgium']) | ||||
|             ->setCountryCode('BE'); | ||||
|         $postCode = new PostalCode(); | ||||
|         $postCode->setName('Locality') | ||||
|             ->setCode('012345') | ||||
|             ->setCountry($country); | ||||
|  | ||||
|         $addr->setStreet('Rue ABC') | ||||
|             ->setStreetNumber('5') | ||||
|             ->setPostcode($postCode); | ||||
|  | ||||
|         $addr->setSteps('4'); | ||||
|  | ||||
|         yield [$addr, 'esc 4 — Rue ABC, 5 — 012345 Locality — Belgium']; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider addressDataProviderFRWithSteps | ||||
|      */ | ||||
| @@ -320,4 +300,24 @@ final class AddressRenderTest extends KernelTestCase | ||||
|  | ||||
|         $this->assertEquals($expectedString, $renderer->renderString($addr, [])); | ||||
|     } | ||||
|  | ||||
|     public static function addressDataProviderFRWithSteps(): \Iterator | ||||
|     { | ||||
|         $addr = new Address(); | ||||
|         $country = (new Country()) | ||||
|             ->setName(['fr' => 'France']) | ||||
|             ->setCountryCode('FR'); | ||||
|         $postCode = new PostalCode(); | ||||
|         $postCode->setName('Locality') | ||||
|             ->setCode('012345') | ||||
|             ->setCountry($country); | ||||
|  | ||||
|         $addr->setStreet('Rue ABC') | ||||
|             ->setStreetNumber('5') | ||||
|             ->setPostcode($postCode); | ||||
|  | ||||
|         $addr->setSteps('4'); | ||||
|  | ||||
|         yield [$addr, 'esc 4 — 5, Rue ABC — 012345 Locality — France']; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -116,6 +116,20 @@ class EntityWorkflowGuardTransitionTest extends TestCase | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public static function provideBlockingTransition(): iterable | ||||
|     { | ||||
|         yield [self::buildEntityWorkflow([new User()]), 'transition1', new User(), false, 'f3eeb57c-7532-11ec-9495-e7942a2ac7bc']; | ||||
|         yield [self::buildEntityWorkflow([]), 'transition1', null, false, 'd9e39a18-704c-11ef-b235-8fe0619caee7']; | ||||
|         yield [self::buildEntityWorkflow([new User()]), 'transition1', null, false, 'd9e39a18-704c-11ef-b235-8fe0619caee7']; | ||||
|         yield [self::buildEntityWorkflow([$user = new User()]), 'transition3', $user, false, '5b6b95e0-704d-11ef-a5a9-4b6fc11a8eeb']; | ||||
|         yield [self::buildEntityWorkflow([$user = new User()]), 'transition3', $user, true, '5b6b95e0-704d-11ef-a5a9-4b6fc11a8eeb']; | ||||
|  | ||||
|         $userGroup = new UserGroup(); | ||||
|         $userGroup->addUser(new User()); | ||||
|  | ||||
|         yield [self::buildEntityWorkflow([$userGroup]), 'transition1', new User(), false, 'f3eeb57c-7532-11ec-9495-e7942a2ac7bc']; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider provideValidTransition | ||||
|      */ | ||||
| @@ -139,20 +153,6 @@ class EntityWorkflowGuardTransitionTest extends TestCase | ||||
|         self::assertEquals($newStep, $entityWorkflow->getStep()); | ||||
|     } | ||||
|  | ||||
|     public static function provideBlockingTransition(): iterable | ||||
|     { | ||||
|         yield [self::buildEntityWorkflow([new User()]), 'transition1', new User(), false, 'f3eeb57c-7532-11ec-9495-e7942a2ac7bc']; | ||||
|         yield [self::buildEntityWorkflow([]), 'transition1', null, false, 'd9e39a18-704c-11ef-b235-8fe0619caee7']; | ||||
|         yield [self::buildEntityWorkflow([new User()]), 'transition1', null, false, 'd9e39a18-704c-11ef-b235-8fe0619caee7']; | ||||
|         yield [self::buildEntityWorkflow([$user = new User()]), 'transition3', $user, false, '5b6b95e0-704d-11ef-a5a9-4b6fc11a8eeb']; | ||||
|         yield [self::buildEntityWorkflow([$user = new User()]), 'transition3', $user, true, '5b6b95e0-704d-11ef-a5a9-4b6fc11a8eeb']; | ||||
|  | ||||
|         $userGroup = new UserGroup(); | ||||
|         $userGroup->addUser(new User()); | ||||
|  | ||||
|         yield [self::buildEntityWorkflow([$userGroup]), 'transition1', new User(), false, 'f3eeb57c-7532-11ec-9495-e7942a2ac7bc']; | ||||
|     } | ||||
|  | ||||
|     public static function provideValidTransition(): iterable | ||||
|     { | ||||
|         yield [self::buildEntityWorkflow([$u = new User()]), 'transition1', $u, false, 'step1']; | ||||
|   | ||||
| @@ -75,45 +75,6 @@ class EntityWorkflowGuardUnsignedTransitionTest extends TestCase | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider guardWaitingForSignatureWithPermissionToApplyAllTransitionsProvider | ||||
|      */ | ||||
|     public function testGuardWaitingForSignatureWithPermissionToApplyAllTransitions(EntityWorkflow $entityWorkflow, string $transition, bool $expectIsGranted, string $message) | ||||
|     { | ||||
|         $chillEntityRender = $this->prophesize(ChillEntityRenderManagerInterface::class); | ||||
|         $chillEntityRender->renderString(Argument::type('object'), Argument::type('array'))->will(fn ($args) => spl_object_hash($args[0])); | ||||
|  | ||||
|         $security = $this->prophesize(Security::class); | ||||
|         $isGranted = $security->isGranted(EntityWorkflowTransitionVoter::APPLY_ALL_TRANSITIONS, Argument::type(EntityWorkflow::class)); | ||||
|         if ($expectIsGranted) { | ||||
|             $isGranted->shouldBeCalled(); | ||||
|         } | ||||
|         $isGranted->willReturn(true); | ||||
|  | ||||
|         $registry = self::buildRegistry($chillEntityRender->reveal(), $security->reveal()); | ||||
|  | ||||
|         $workflow = $registry->get($entityWorkflow, 'dummy'); | ||||
|  | ||||
|         $actual = $workflow->buildTransitionBlockerList($entityWorkflow, $transition); | ||||
|  | ||||
|         self::assertCount(0, $actual, $message); | ||||
|     } | ||||
|  | ||||
|     public static function guardWaitingForSignatureWithPermissionToApplyAllTransitionsProvider(): iterable | ||||
|     { | ||||
|         $registry = self::buildRegistry(); | ||||
|         $entityWorkflow = new EntityWorkflow(); | ||||
|         $dto = new WorkflowTransitionContextDTO($entityWorkflow); | ||||
|         $dto->futureDestUsers = [$user = new User()]; | ||||
|         $dto->futureUserSignature = $user; | ||||
|  | ||||
|         $workflow = $registry->get($entityWorkflow, 'dummy'); | ||||
|         $workflow->apply($entityWorkflow, 'to_signature', ['context' => $dto, 'transitionAt' => new \DateTimeImmutable(), 'byUser' => new User(), 'transition' => 'to_signature']); | ||||
|  | ||||
|         yield [$entityWorkflow, 'to_post-signature', true, 'A transition forward is allowed, even if a signature is pending, because the user has permission to apply all transition']; | ||||
|         yield [$entityWorkflow, 'to_cancel', false, 'A transition backward is allowed, even if a signature is pending']; | ||||
|     } | ||||
|  | ||||
|     public static function guardWaitingForSignatureWithoutPermissionToApplyAllTransitionsProvider(): iterable | ||||
|     { | ||||
|         $registry = self::buildRegistry(); | ||||
| @@ -156,6 +117,45 @@ class EntityWorkflowGuardUnsignedTransitionTest extends TestCase | ||||
|         yield [$entityWorkflow, 'to_cancel', [], [], 'A transition backward is allowed, even if a signature is pending']; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider guardWaitingForSignatureWithPermissionToApplyAllTransitionsProvider | ||||
|      */ | ||||
|     public function testGuardWaitingForSignatureWithPermissionToApplyAllTransitions(EntityWorkflow $entityWorkflow, string $transition, bool $expectIsGranted, string $message) | ||||
|     { | ||||
|         $chillEntityRender = $this->prophesize(ChillEntityRenderManagerInterface::class); | ||||
|         $chillEntityRender->renderString(Argument::type('object'), Argument::type('array'))->will(fn ($args) => spl_object_hash($args[0])); | ||||
|  | ||||
|         $security = $this->prophesize(Security::class); | ||||
|         $isGranted = $security->isGranted(EntityWorkflowTransitionVoter::APPLY_ALL_TRANSITIONS, Argument::type(EntityWorkflow::class)); | ||||
|         if ($expectIsGranted) { | ||||
|             $isGranted->shouldBeCalled(); | ||||
|         } | ||||
|         $isGranted->willReturn(true); | ||||
|  | ||||
|         $registry = self::buildRegistry($chillEntityRender->reveal(), $security->reveal()); | ||||
|  | ||||
|         $workflow = $registry->get($entityWorkflow, 'dummy'); | ||||
|  | ||||
|         $actual = $workflow->buildTransitionBlockerList($entityWorkflow, $transition); | ||||
|  | ||||
|         self::assertCount(0, $actual, $message); | ||||
|     } | ||||
|  | ||||
|     public static function guardWaitingForSignatureWithPermissionToApplyAllTransitionsProvider(): iterable | ||||
|     { | ||||
|         $registry = self::buildRegistry(); | ||||
|         $entityWorkflow = new EntityWorkflow(); | ||||
|         $dto = new WorkflowTransitionContextDTO($entityWorkflow); | ||||
|         $dto->futureDestUsers = [$user = new User()]; | ||||
|         $dto->futureUserSignature = $user; | ||||
|  | ||||
|         $workflow = $registry->get($entityWorkflow, 'dummy'); | ||||
|         $workflow->apply($entityWorkflow, 'to_signature', ['context' => $dto, 'transitionAt' => new \DateTimeImmutable(), 'byUser' => new User(), 'transition' => 'to_signature']); | ||||
|  | ||||
|         yield [$entityWorkflow, 'to_post-signature', true, 'A transition forward is allowed, even if a signature is pending, because the user has permission to apply all transition']; | ||||
|         yield [$entityWorkflow, 'to_cancel', false, 'A transition backward is allowed, even if a signature is pending']; | ||||
|     } | ||||
|  | ||||
|     private static function buildRegistry(?ChillEntityRenderManagerInterface $chillEntityRender = null, ?Security $security = null): Registry | ||||
|     { | ||||
|         $builder = new DefinitionBuilder(); | ||||
|   | ||||
| @@ -61,49 +61,6 @@ class WorkflowRelatedEntityPermissionHelperTest extends TestCase | ||||
|         self::assertEquals($expected, $helper->isAllowedByWorkflowForReadOperation(new \stdClass()), $message); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider provideDataAllowedByWorkflowWriteOperation | ||||
|      * | ||||
|      * @param list<EntityWorkflow> $entityWorkflows | ||||
|      */ | ||||
|     public function testAllowedByWorkflowWrite( | ||||
|         array $entityWorkflows, | ||||
|         User $user, | ||||
|         string $expected, | ||||
|         ?\DateTimeImmutable $atDate, | ||||
|         string $message, | ||||
|     ): void { | ||||
|         // all entities must have this workflow name, so we are ok to set it here | ||||
|         foreach ($entityWorkflows as $entityWorkflow) { | ||||
|             $entityWorkflow->setWorkflowName('dummy'); | ||||
|         } | ||||
|         $helper = $this->buildHelper($entityWorkflows, $user, $atDate); | ||||
|  | ||||
|         self::assertEquals($expected, $helper->isAllowedByWorkflowForWriteOperation(new \stdClass()), $message); | ||||
|     } | ||||
|  | ||||
|     public function testNoWorkflow(): void | ||||
|     { | ||||
|         $helper = $this->buildHelper([], new User(), null); | ||||
|  | ||||
|         self::assertEquals(WorkflowRelatedEntityPermissionHelper::ABSTAIN, $helper->isAllowedByWorkflowForWriteOperation(new \stdClass())); | ||||
|         self::assertEquals(WorkflowRelatedEntityPermissionHelper::ABSTAIN, $helper->isAllowedByWorkflowForReadOperation(new \stdClass())); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param list<EntityWorkflow> $entityWorkflows | ||||
|      */ | ||||
|     private function buildHelper(array $entityWorkflows, User $user, ?\DateTimeImmutable $atDateTime): WorkflowRelatedEntityPermissionHelper | ||||
|     { | ||||
|         $security = $this->prophesize(Security::class); | ||||
|         $security->getUser()->willReturn($user); | ||||
|  | ||||
|         $entityWorkflowManager = $this->prophesize(EntityWorkflowManager::class); | ||||
|         $entityWorkflowManager->findByRelatedEntity(Argument::type('object'))->willReturn($entityWorkflows); | ||||
|  | ||||
|         return new WorkflowRelatedEntityPermissionHelper($security->reveal(), $entityWorkflowManager->reveal(), $this->buildRegistry(), new MockClock($atDateTime ?? new \DateTimeImmutable())); | ||||
|     } | ||||
|  | ||||
|     public static function provideDataAllowedByWorkflowReadOperation(): iterable | ||||
|     { | ||||
|         $entityWorkflow = new EntityWorkflow(); | ||||
| @@ -164,6 +121,27 @@ class WorkflowRelatedEntityPermissionHelperTest extends TestCase | ||||
|             'force grant because there is a signature for person, already signed, a short time ago']; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider provideDataAllowedByWorkflowWriteOperation | ||||
|      * | ||||
|      * @param list<EntityWorkflow> $entityWorkflows | ||||
|      */ | ||||
|     public function testAllowedByWorkflowWrite( | ||||
|         array $entityWorkflows, | ||||
|         User $user, | ||||
|         string $expected, | ||||
|         ?\DateTimeImmutable $atDate, | ||||
|         string $message, | ||||
|     ): void { | ||||
|         // all entities must have this workflow name, so we are ok to set it here | ||||
|         foreach ($entityWorkflows as $entityWorkflow) { | ||||
|             $entityWorkflow->setWorkflowName('dummy'); | ||||
|         } | ||||
|         $helper = $this->buildHelper($entityWorkflows, $user, $atDate); | ||||
|  | ||||
|         self::assertEquals($expected, $helper->isAllowedByWorkflowForWriteOperation(new \stdClass()), $message); | ||||
|     } | ||||
|  | ||||
|     public static function provideDataAllowedByWorkflowWriteOperation(): iterable | ||||
|     { | ||||
|         $entityWorkflow = new EntityWorkflow(); | ||||
| @@ -256,6 +234,28 @@ class WorkflowRelatedEntityPermissionHelperTest extends TestCase | ||||
|             'abstain: there is a signature on a canceled workflow']; | ||||
|     } | ||||
|  | ||||
|     public function testNoWorkflow(): void | ||||
|     { | ||||
|         $helper = $this->buildHelper([], new User(), null); | ||||
|  | ||||
|         self::assertEquals(WorkflowRelatedEntityPermissionHelper::ABSTAIN, $helper->isAllowedByWorkflowForWriteOperation(new \stdClass())); | ||||
|         self::assertEquals(WorkflowRelatedEntityPermissionHelper::ABSTAIN, $helper->isAllowedByWorkflowForReadOperation(new \stdClass())); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param list<EntityWorkflow> $entityWorkflows | ||||
|      */ | ||||
|     private function buildHelper(array $entityWorkflows, User $user, ?\DateTimeImmutable $atDateTime): WorkflowRelatedEntityPermissionHelper | ||||
|     { | ||||
|         $security = $this->prophesize(Security::class); | ||||
|         $security->getUser()->willReturn($user); | ||||
|  | ||||
|         $entityWorkflowManager = $this->prophesize(EntityWorkflowManager::class); | ||||
|         $entityWorkflowManager->findByRelatedEntity(Argument::type('object'))->willReturn($entityWorkflows); | ||||
|  | ||||
|         return new WorkflowRelatedEntityPermissionHelper($security->reveal(), $entityWorkflowManager->reveal(), $this->buildRegistry(), new MockClock($atDateTime ?? new \DateTimeImmutable())); | ||||
|     } | ||||
|  | ||||
|     private static function buildRegistry(): Registry | ||||
|     { | ||||
|         $builder = new DefinitionBuilder(); | ||||
|   | ||||
| @@ -16,10 +16,8 @@ use Chill\MainBundle\Form\Type\CommentType; | ||||
| use Chill\PersonBundle\Entity\Person\PersonResource; | ||||
| use Chill\PersonBundle\Entity\Person\PersonResourceKind; | ||||
| use Chill\PersonBundle\Form\Type\PickPersonDynamicType; | ||||
| use Chill\PersonBundle\Templating\Entity\PersonRenderInterface; | ||||
| use Chill\PersonBundle\Templating\Entity\ResourceKindRender; | ||||
| use Chill\ThirdPartyBundle\Form\Type\PickThirdpartyDynamicType; | ||||
| use Chill\ThirdPartyBundle\Templating\Entity\ThirdPartyRender; | ||||
| use Doctrine\ORM\EntityRepository; | ||||
| use Symfony\Bridge\Doctrine\Form\Type\EntityType; | ||||
| use Symfony\Component\Form\AbstractType; | ||||
| @@ -29,7 +27,7 @@ use Symfony\Contracts\Translation\TranslatorInterface; | ||||
|  | ||||
| final class PersonResourceType extends AbstractType | ||||
| { | ||||
|     public function __construct(private readonly ResourceKindRender $resourceKindRender, private readonly PersonRenderInterface $personRender, private readonly ThirdPartyRender $thirdPartyRender, private readonly TranslatorInterface $translator) {} | ||||
|     public function __construct(private readonly ResourceKindRender $resourceKindRender, private readonly TranslatorInterface $translator) {} | ||||
|  | ||||
|     public function buildForm(FormBuilderInterface $builder, array $options) | ||||
|     { | ||||
| @@ -52,13 +50,13 @@ final class PersonResourceType extends AbstractType | ||||
|                 }, | ||||
|             ]) | ||||
|             ->add('person', PickPersonDynamicType::class, [ | ||||
|                 'label' => 'Usager', | ||||
|                 'label' => $this->translator->trans('person_resource.person_non_prof'), | ||||
|             ]) | ||||
|             ->add('thirdparty', PickThirdpartyDynamicType::class, [ | ||||
|                 'label' => 'Tiers', | ||||
|                 'label' => $this->translator->trans('person_resource.thirdparty_prof'), | ||||
|             ]) | ||||
|             ->add('freetext', ChillTextareaType::class, [ | ||||
|                 'label' => 'Description libre', | ||||
|                 'label' => $this->translator->trans('person_resource.freetext'), | ||||
|                 'required' => false, | ||||
|             ]) | ||||
|             ->add('comment', CommentType::class, [ | ||||
|   | ||||
| @@ -10,28 +10,28 @@ | ||||
|                         <div class="form-check"> | ||||
|                             {% if resource is defined and resource.person is not null %} | ||||
|                                 <input checked type="radio" id="chill_personbundle_person_resource_linkedEntity_0" name="linked-entity" class="form-check-input" value="person" {% if form.vars.submitted and app.request.request.get('linked-entity', null) == 'person' %}checked{% endif %}/> | ||||
|                                 <label class="form-check-label" for="chill_personbundle_person_resource_linkedEntity_0">Usager</label> | ||||
|                                 <label class="form-check-label" for="chill_personbundle_person_resource_linkedEntity_0">{{ 'person_resource.person_non_prof'|trans }}</label> | ||||
|                             {% else %} | ||||
|                                 <input type="radio" id="chill_personbundle_person_resource_linkedEntity_0" name="linked-entity" class="form-check-input" value="person" /> | ||||
|                                 <label class="form-check-label" for="chill_personbundle_person_resource_linkedEntity_0">Usager</label> | ||||
|                                 <label class="form-check-label" for="chill_personbundle_person_resource_linkedEntity_0">{{ 'person_resource.person_non_prof'|trans }}</label> | ||||
|                             {% endif %} | ||||
|                         </div> | ||||
|                         <div class="form-check"> | ||||
|                             {% if resource is defined and resource.thirdparty is not null %} | ||||
|                                 <input checked type="radio" id="chill_personbundle_person_resource_linkedEntity_1" name="linked-entity" class="form-check-input" value="thirdparty" {% if form.vars.submitted and app.request.request.get('linked-entity', null) == 'thirdparty' %}checked{% endif %}/> | ||||
|                                 <label class="form-check-label" for="chill_personbundle_person_resource_linkedEntity_1">Tiers</label> | ||||
|                                 <label class="form-check-label" for="chill_personbundle_person_resource_linkedEntity_1">{{ 'person_resource.thirdparty_prof'|trans }}</label> | ||||
|                             {% else %} | ||||
|                                 <input type="radio" id="chill_personbundle_person_resource_linkedEntity_1" name="linked-entity" class="form-check-input" value="thirdparty" /> | ||||
|                                 <label class="form-check-label" for="chill_personbundle_person_resource_linkedEntity_1">Tiers</label> | ||||
|                                 <label class="form-check-label" for="chill_personbundle_person_resource_linkedEntity_1">{{ 'person_resource.thirdparty_prof'|trans }}</label> | ||||
|                             {% endif %} | ||||
|                         </div> | ||||
|                         <div class="form-check"> | ||||
|                             {% if resource is defined and resource.freeText is not null %} | ||||
|                                 <input checked type="radio" id="chill_personbundle_person_resource_linkedEntity_2" name="linked-entity" class="form-check-input" value="freetext" {% if form.vars.submitted and app.request.request.get('linked-entity', null) == 'thirdparty' %}checked{% endif %}/> | ||||
|                                 <label class="form-check-label" for="chill_personbundle_person_resource_linkedEntity_2">Description libre</label> | ||||
|                                 <label class="form-check-label" for="chill_personbundle_person_resource_linkedEntity_2">{{ 'person_resource.freetext'|trans }}</label> | ||||
|                             {% else %} | ||||
|                                 <input type="radio" id="chill_personbundle_person_resource_linkedEntity_2" name="linked-entity" class="form-check-input" value="freetext" /> | ||||
|                                 <label class="form-check-label" for="chill_personbundle_person_resource_linkedEntity_2">Description libre</label> | ||||
|                                 <label class="form-check-label" for="chill_personbundle_person_resource_linkedEntity_2">{{ 'person_resource.freetext'|trans }}</label> | ||||
|                             {% endif %} | ||||
|                         </div> | ||||
|                     </div> | ||||
|   | ||||
| @@ -99,81 +99,6 @@ class PersonMoveTest extends KernelTestCase | ||||
|         self::assertNotNull($personB?->getId(), $message); | ||||
|     } | ||||
|  | ||||
|     public function testMovePersonCenterHistory(): void | ||||
|     { | ||||
|         $personA = new Person(); | ||||
|         $personB = new Person(); | ||||
|         [$centerA, $centerB] = $this->centerRepository->findAll(); | ||||
|  | ||||
|         $this->em->persist($personA); | ||||
|         $this->em->persist($personB); | ||||
|  | ||||
|         $personCenterHistoryAFirst = (new Person\PersonCenterHistory())->setCenter($centerA) | ||||
|             ->setStartDate(new \DateTimeImmutable('2023-01-01')) | ||||
|             ->setEndDate(new \DateTimeImmutable('2023-06-30')); | ||||
|         $personCenterHistoryASecond = (new Person\PersonCenterHistory())->setCenter($centerB) | ||||
|             ->setStartDate(new \DateTimeImmutable('2023-06-30')) | ||||
|             ->setEndDate(new \DateTimeImmutable('2023-09-30')); | ||||
|         $personCenterHistoryBFirst = (new Person\PersonCenterHistory())->setCenter($centerA) | ||||
|             ->setStartDate(new \DateTimeImmutable('2023-03-01')) | ||||
|             ->setEndDate(new \DateTimeImmutable('2023-07-15')); | ||||
|         $personCenterHistoryBSecond = (new Person\PersonCenterHistory())->setCenter($centerB) | ||||
|             ->setStartDate(new \DateTimeImmutable('2023-07-15')) | ||||
|             ->setEndDate(new \DateTimeImmutable('2023-09-30')); | ||||
|  | ||||
|         $this->em->persist($personCenterHistoryAFirst); | ||||
|         $this->em->persist($personCenterHistoryASecond); | ||||
|         $this->em->persist($personCenterHistoryBFirst); | ||||
|         $this->em->persist($personCenterHistoryBSecond); | ||||
|  | ||||
|         $personA->addCenterHistory($personCenterHistoryAFirst); | ||||
|         $personA->addCenterHistory($personCenterHistoryASecond); | ||||
|         $personB->addCenterHistory($personCenterHistoryBFirst); | ||||
|         $personB->addCenterHistory($personCenterHistoryBSecond); | ||||
|  | ||||
|         $this->em->flush(); | ||||
|         $this->em->clear(); | ||||
|  | ||||
|         $move = new PersonMove($this->em, $this->personMoveManager, $this->eventDispatcher); | ||||
|         $sqls = $move->getSQL($personA, $personB); | ||||
|         $this->em->getConnection()->transactional(function (Connection $conn) use ($sqls) { | ||||
|             foreach ($sqls as $sql) { | ||||
|                 $conn->executeStatement($sql); | ||||
|             } | ||||
|         }); | ||||
|  | ||||
|         $personsByIdOfA = $this->em->createQuery('SELECT p FROM '.Person::class.' p WHERE p.id = :id') | ||||
|             ->setParameter('id', $personA->getId()) | ||||
|             ->getResult(); | ||||
|         /** @var Person $personB */ | ||||
|         $personB = $this->em->find(Person::class, $personB->getId()); | ||||
|         $message = 'Move persons with overlapping center histories'; | ||||
|  | ||||
|         self::assertCount(0, $personsByIdOfA); | ||||
|         self::assertNotNull($personB?->getId(), $message); | ||||
|  | ||||
|         $centersHistories = $this->personCenterHistory->findBy(['person' => $personB]); | ||||
|  | ||||
|         // compute the oldest center history | ||||
|         $oldestCenterHistory = null; | ||||
|         foreach ($centersHistories as $centerHistory) { | ||||
|             $this->em->refresh($centerHistory); | ||||
|             if (null === $oldestCenterHistory || ($oldestCenterHistory instanceof Person\PersonCenterHistory && $oldestCenterHistory->getStartDate() >= $centerHistory->getStartDate())) { | ||||
|                 $oldestCenterHistory = $centerHistory; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         self::assertCount(2, $centersHistories); | ||||
|         self::assertEquals('2023-01-01', $oldestCenterHistory?->getStartDate()->format('Y-m-d')); | ||||
|  | ||||
|         self::$entitiesToDelete[] = [Person::class, $personA]; | ||||
|         self::$entitiesToDelete[] = [Person::class, $personB]; | ||||
|         self::$entitiesToDelete[] = [Person\PersonCenterHistory::class, $personCenterHistoryAFirst]; | ||||
|         self::$entitiesToDelete[] = [Person\PersonCenterHistory::class, $personCenterHistoryASecond]; | ||||
|         self::$entitiesToDelete[] = [Person\PersonCenterHistory::class, $personCenterHistoryBFirst]; | ||||
|         self::$entitiesToDelete[] = [Person\PersonCenterHistory::class, $personCenterHistoryBSecond]; | ||||
|     } | ||||
|  | ||||
|     public static function dataProviderMovePerson(): iterable | ||||
|     { | ||||
|         self::bootKernel(); | ||||
| @@ -280,4 +205,79 @@ class PersonMoveTest extends KernelTestCase | ||||
|         $em->flush(); | ||||
|         $em->clear(); | ||||
|     } | ||||
|  | ||||
|     public function testMovePersonCenterHistory(): void | ||||
|     { | ||||
|         $personA = new Person(); | ||||
|         $personB = new Person(); | ||||
|         [$centerA, $centerB] = $this->centerRepository->findAll(); | ||||
|  | ||||
|         $this->em->persist($personA); | ||||
|         $this->em->persist($personB); | ||||
|  | ||||
|         $personCenterHistoryAFirst = (new Person\PersonCenterHistory())->setCenter($centerA) | ||||
|             ->setStartDate(new \DateTimeImmutable('2023-01-01')) | ||||
|             ->setEndDate(new \DateTimeImmutable('2023-06-30')); | ||||
|         $personCenterHistoryASecond = (new Person\PersonCenterHistory())->setCenter($centerB) | ||||
|             ->setStartDate(new \DateTimeImmutable('2023-06-30')) | ||||
|             ->setEndDate(new \DateTimeImmutable('2023-09-30')); | ||||
|         $personCenterHistoryBFirst = (new Person\PersonCenterHistory())->setCenter($centerA) | ||||
|             ->setStartDate(new \DateTimeImmutable('2023-03-01')) | ||||
|             ->setEndDate(new \DateTimeImmutable('2023-07-15')); | ||||
|         $personCenterHistoryBSecond = (new Person\PersonCenterHistory())->setCenter($centerB) | ||||
|             ->setStartDate(new \DateTimeImmutable('2023-07-15')) | ||||
|             ->setEndDate(new \DateTimeImmutable('2023-09-30')); | ||||
|  | ||||
|         $this->em->persist($personCenterHistoryAFirst); | ||||
|         $this->em->persist($personCenterHistoryASecond); | ||||
|         $this->em->persist($personCenterHistoryBFirst); | ||||
|         $this->em->persist($personCenterHistoryBSecond); | ||||
|  | ||||
|         $personA->addCenterHistory($personCenterHistoryAFirst); | ||||
|         $personA->addCenterHistory($personCenterHistoryASecond); | ||||
|         $personB->addCenterHistory($personCenterHistoryBFirst); | ||||
|         $personB->addCenterHistory($personCenterHistoryBSecond); | ||||
|  | ||||
|         $this->em->flush(); | ||||
|         $this->em->clear(); | ||||
|  | ||||
|         $move = new PersonMove($this->em, $this->personMoveManager, $this->eventDispatcher); | ||||
|         $sqls = $move->getSQL($personA, $personB); | ||||
|         $this->em->getConnection()->transactional(function (Connection $conn) use ($sqls) { | ||||
|             foreach ($sqls as $sql) { | ||||
|                 $conn->executeStatement($sql); | ||||
|             } | ||||
|         }); | ||||
|  | ||||
|         $personsByIdOfA = $this->em->createQuery('SELECT p FROM '.Person::class.' p WHERE p.id = :id') | ||||
|             ->setParameter('id', $personA->getId()) | ||||
|             ->getResult(); | ||||
|         /** @var Person $personB */ | ||||
|         $personB = $this->em->find(Person::class, $personB->getId()); | ||||
|         $message = 'Move persons with overlapping center histories'; | ||||
|  | ||||
|         self::assertCount(0, $personsByIdOfA); | ||||
|         self::assertNotNull($personB?->getId(), $message); | ||||
|  | ||||
|         $centersHistories = $this->personCenterHistory->findBy(['person' => $personB]); | ||||
|  | ||||
|         // compute the oldest center history | ||||
|         $oldestCenterHistory = null; | ||||
|         foreach ($centersHistories as $centerHistory) { | ||||
|             $this->em->refresh($centerHistory); | ||||
|             if (null === $oldestCenterHistory || ($oldestCenterHistory instanceof Person\PersonCenterHistory && $oldestCenterHistory->getStartDate() >= $centerHistory->getStartDate())) { | ||||
|                 $oldestCenterHistory = $centerHistory; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         self::assertCount(2, $centersHistories); | ||||
|         self::assertEquals('2023-01-01', $oldestCenterHistory?->getStartDate()->format('Y-m-d')); | ||||
|  | ||||
|         self::$entitiesToDelete[] = [Person::class, $personA]; | ||||
|         self::$entitiesToDelete[] = [Person::class, $personB]; | ||||
|         self::$entitiesToDelete[] = [Person\PersonCenterHistory::class, $personCenterHistoryAFirst]; | ||||
|         self::$entitiesToDelete[] = [Person\PersonCenterHistory::class, $personCenterHistoryASecond]; | ||||
|         self::$entitiesToDelete[] = [Person\PersonCenterHistory::class, $personCenterHistoryBFirst]; | ||||
|         self::$entitiesToDelete[] = [Person\PersonCenterHistory::class, $personCenterHistoryBSecond]; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -48,251 +48,6 @@ final class AccompanyingCourseApiControllerTest extends WebTestCase | ||||
|         self::ensureKernelShutdown(); | ||||
|     } | ||||
|  | ||||
|     public static function dataGenerateNewAccompanyingCourse() | ||||
|     { | ||||
|         self::bootKernel(); | ||||
|         $em = self::getContainer()->get(EntityManagerInterface::class); | ||||
|  | ||||
|         $period = new AccompanyingPeriod(new \DateTime('1 week ago')); | ||||
|         $user = $em->getRepository(User::class) | ||||
|             ->findOneByUsernameCanonical('center a_social'); | ||||
|         $period->setCreatedBy($user); | ||||
|         // $period->setCreatedAt(new \DateTime('yesterday')); | ||||
|  | ||||
|         $center = $em->getRepository(Center::class) | ||||
|             ->findOneBy(['name' => 'Center A']); | ||||
|  | ||||
|         $personIds = $em->createQuery('SELECT p.id FROM '. | ||||
|             Person::class.' p JOIN p.centerCurrent cc'. | ||||
|             ' WHERE cc.center = :center') | ||||
|             ->setParameter('center', $center) | ||||
|             ->setMaxResults(100) | ||||
|             ->getScalarResult(); | ||||
|  | ||||
|         // create a random order | ||||
|         shuffle($personIds); | ||||
|  | ||||
|         for ($i = 0; 2 > $i; ++$i) { | ||||
|             $person = $em->getRepository(Person::class)->find(\array_pop($personIds)); | ||||
|             $period->addPerson($person); | ||||
|         } | ||||
|  | ||||
|         $em->persist($period); | ||||
|         $em->flush(); | ||||
|  | ||||
|         yield [$period]; | ||||
|  | ||||
|         self::ensureKernelShutdown(); | ||||
|     } | ||||
|  | ||||
|     public static function dataGenerateRandomAccompanyingCourse() | ||||
|     { | ||||
|         // note about max result for person query, and maxGenerated: | ||||
|         // | ||||
|         // in the final loop, an id is popped out of the personIds array twice: | ||||
|         // | ||||
|         // * one for getting the person, which will in turn provide his accompanying period; | ||||
|         // * one for getting the personId to populate to the data manager | ||||
|         // | ||||
|         // Ensure to keep always $maxGenerated to the double of $maxResults. x8 is a good compromize :) | ||||
|         $maxGenerated = 3; | ||||
|         $maxResults = $maxGenerated * 8; | ||||
|  | ||||
|         self::bootKernel(); | ||||
|         $em = self::getContainer()->get(EntityManagerInterface::class); | ||||
|         $center = $em->getRepository(Center::class) | ||||
|             ->findOneBy(['name' => 'Center A']); | ||||
|  | ||||
|         $qb = $em->createQueryBuilder(); | ||||
|         $personIds = $qb | ||||
|             ->select('p.id') | ||||
|             ->distinct(true) | ||||
|             ->from(Person::class, 'p') | ||||
|             ->join('p.accompanyingPeriodParticipations', 'participation') | ||||
|             ->join('participation.accompanyingPeriod', 'ap') | ||||
|             ->join('p.centerCurrent', 'cc') | ||||
|             ->where( | ||||
|                 $qb->expr()->eq( | ||||
|                     'cc.center', | ||||
|                     ':center' | ||||
|                 ) | ||||
|             ) | ||||
|             ->andWhere( | ||||
|                 $qb->expr()->gt( | ||||
|                     'SIZE(p.accompanyingPeriodParticipations)', | ||||
|                     0 | ||||
|                 ) | ||||
|             ) | ||||
|             ->andWhere( | ||||
|                 $qb->expr()->eq('ap.step', ':step') | ||||
|             ) | ||||
|             ->setParameter('center', $center) | ||||
|             ->setParameter('step', AccompanyingPeriod::STEP_CONFIRMED) | ||||
|             ->setMaxResults($maxResults) | ||||
|             ->getQuery() | ||||
|             ->getScalarResult(); | ||||
|  | ||||
|         // create a random order | ||||
|         shuffle($personIds); | ||||
|  | ||||
|         $nbGenerated = 0; | ||||
|  | ||||
|         while ($nbGenerated < $maxGenerated) { | ||||
|             $id = \array_pop($personIds)['id']; | ||||
|  | ||||
|             $person = $em->getRepository(Person::class) | ||||
|                 ->find($id); | ||||
|             $periods = $person->getAccompanyingPeriods(); | ||||
|  | ||||
|             yield [\array_pop($personIds)['id'], $periods[\array_rand($periods)]->getId()]; | ||||
|  | ||||
|             ++$nbGenerated; | ||||
|         } | ||||
|  | ||||
|         self::ensureKernelShutdown(); | ||||
|     } | ||||
|  | ||||
|     public static function dataGenerateRandomAccompanyingCourseWithSocialIssue() | ||||
|     { | ||||
|         // note about max result for person query, and maxGenerated: | ||||
|         // | ||||
|         // in the final loop, an id is popped out of the personIds array twice: | ||||
|         // | ||||
|         // * one for getting the person, which will in turn provide his accompanying period; | ||||
|         // * one for getting the personId to populate to the data manager | ||||
|         // | ||||
|         // Ensure to keep always $maxGenerated to the double of $maxResults. x8 is a good compromize :) | ||||
|         $maxGenerated = 3; | ||||
|         $maxResults = $maxGenerated * 8; | ||||
|  | ||||
|         self::bootKernel(); | ||||
|         $em = self::getContainer()->get(EntityManagerInterface::class); | ||||
|         $center = $em->getRepository(Center::class) | ||||
|             ->findOneBy(['name' => 'Center A']); | ||||
|         $qb = $em->createQueryBuilder(); | ||||
|  | ||||
|         $personIds = $qb | ||||
|             ->select('p.id') | ||||
|             ->distinct(true) | ||||
|             ->from(Person::class, 'p') | ||||
|             ->join('p.accompanyingPeriodParticipations', 'participation') | ||||
|             ->join('participation.accompanyingPeriod', 'ap') | ||||
|             ->join('p.centerCurrent', 'cc') | ||||
|             ->where( | ||||
|                 $qb->expr()->eq( | ||||
|                     'cc.center', | ||||
|                     ':center' | ||||
|                 ) | ||||
|             ) | ||||
|             ->andWhere( | ||||
|                 $qb->expr()->gt( | ||||
|                     'SIZE(p.accompanyingPeriodParticipations)', | ||||
|                     0 | ||||
|                 ) | ||||
|             ) | ||||
|             ->andWhere( | ||||
|                 $qb->expr()->eq('ap.step', ':step') | ||||
|             ) | ||||
|             ->setParameter('center', $center) | ||||
|             ->setParameter('step', AccompanyingPeriod::STEP_CONFIRMED) | ||||
|             ->setMaxResults($maxResults) | ||||
|             ->getQuery() | ||||
|             ->getScalarResult(); | ||||
|  | ||||
|         // create a random order | ||||
|         shuffle($personIds); | ||||
|  | ||||
|         $socialIssues = $em->createQuery('SELECT s FROM '. | ||||
|             SocialIssue::class.' s ') | ||||
|             ->setMaxResults(10) | ||||
|             ->getResult(); | ||||
|  | ||||
|         $nbGenerated = 0; | ||||
|  | ||||
|         while ($nbGenerated < $maxGenerated) { | ||||
|             $id = \array_pop($personIds)['id']; | ||||
|  | ||||
|             $person = $em->getRepository(Person::class) | ||||
|                 ->find($id); | ||||
|             $periods = $person->getAccompanyingPeriods(); | ||||
|  | ||||
|             yield [$periods[\array_rand($periods)], $socialIssues[\array_rand($socialIssues)]]; | ||||
|  | ||||
|             ++$nbGenerated; | ||||
|         } | ||||
|  | ||||
|         self::ensureKernelShutdown(); | ||||
|     } | ||||
|  | ||||
|     public static function dataGenerateRandomRequestorValidData(): \Iterator | ||||
|     { | ||||
|         $dataLength = 2; | ||||
|         $maxResults = 100; | ||||
|  | ||||
|         self::bootKernel(); | ||||
|         $em = self::getContainer()->get(EntityManagerInterface::class); | ||||
|         $center = $em->getRepository(Center::class) | ||||
|             ->findOneBy(['name' => 'Center A']); | ||||
|         $qb = $em->createQueryBuilder(); | ||||
|  | ||||
|         $personIds = $qb | ||||
|             ->select('p.id') | ||||
|             ->distinct(true) | ||||
|             ->from(Person::class, 'p') | ||||
|             ->join('p.accompanyingPeriodParticipations', 'participation') | ||||
|             ->join('participation.accompanyingPeriod', 'ap') | ||||
|             ->join('p.centerCurrent', 'cc') | ||||
|             ->where( | ||||
|                 $qb->expr()->eq( | ||||
|                     'cc.center', | ||||
|                     ':center' | ||||
|                 ) | ||||
|             ) | ||||
|             ->andWhere( | ||||
|                 $qb->expr()->gt( | ||||
|                     'SIZE(p.accompanyingPeriodParticipations)', | ||||
|                     0 | ||||
|                 ) | ||||
|             ) | ||||
|             ->andWhere( | ||||
|                 $qb->expr()->eq('ap.step', ':step') | ||||
|             ) | ||||
|             ->setParameter('center', $center) | ||||
|             ->setParameter('step', AccompanyingPeriod::STEP_CONFIRMED) | ||||
|             ->setMaxResults($maxResults) | ||||
|             ->getQuery() | ||||
|             ->getScalarResult(); | ||||
|  | ||||
|         // create a random order | ||||
|         shuffle($personIds); | ||||
|  | ||||
|         $thirdPartyIds = $em->createQuery('SELECT t.id FROM '. | ||||
|             ThirdParty::class.' t ') | ||||
|             ->setMaxResults($maxResults) | ||||
|             ->getScalarResult(); | ||||
|  | ||||
|         // create a random order | ||||
|         shuffle($thirdPartyIds); | ||||
|  | ||||
|         $i = 0; | ||||
|  | ||||
|         while ($i <= $dataLength) { | ||||
|             $person = $em->getRepository(Person::class) | ||||
|                 ->find(\array_pop($personIds)['id']); | ||||
|  | ||||
|             if (0 === \count($person->getAccompanyingPeriods())) { | ||||
|                 continue; | ||||
|             } | ||||
|  | ||||
|             $period = $person->getAccompanyingPeriods()[0]; | ||||
|  | ||||
|             yield [$period, \array_pop($personIds)['id'], \array_pop($thirdPartyIds)['id']]; | ||||
|             ++$i; | ||||
|         } | ||||
|  | ||||
|         self::ensureKernelShutdown(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider dataGenerateRandomAccompanyingCourse | ||||
|      */ | ||||
| @@ -403,6 +158,78 @@ final class AccompanyingCourseApiControllerTest extends WebTestCase | ||||
|         $this->assertTrue(\in_array($this->client->getResponse()->getStatusCode(), [200, 422], true)); | ||||
|     } | ||||
|  | ||||
|     public static function dataGenerateRandomAccompanyingCourseWithSocialIssue() | ||||
|     { | ||||
|         // note about max result for person query, and maxGenerated: | ||||
|         // | ||||
|         // in the final loop, an id is popped out of the personIds array twice: | ||||
|         // | ||||
|         // * one for getting the person, which will in turn provide his accompanying period; | ||||
|         // * one for getting the personId to populate to the data manager | ||||
|         // | ||||
|         // Ensure to keep always $maxGenerated to the double of $maxResults. x8 is a good compromize :) | ||||
|         $maxGenerated = 3; | ||||
|         $maxResults = $maxGenerated * 8; | ||||
|  | ||||
|         self::bootKernel(); | ||||
|         $em = self::getContainer()->get(EntityManagerInterface::class); | ||||
|         $center = $em->getRepository(Center::class) | ||||
|             ->findOneBy(['name' => 'Center A']); | ||||
|         $qb = $em->createQueryBuilder(); | ||||
|  | ||||
|         $personIds = $qb | ||||
|             ->select('p.id') | ||||
|             ->distinct(true) | ||||
|             ->from(Person::class, 'p') | ||||
|             ->join('p.accompanyingPeriodParticipations', 'participation') | ||||
|             ->join('participation.accompanyingPeriod', 'ap') | ||||
|             ->join('p.centerCurrent', 'cc') | ||||
|             ->where( | ||||
|                 $qb->expr()->eq( | ||||
|                     'cc.center', | ||||
|                     ':center' | ||||
|                 ) | ||||
|             ) | ||||
|             ->andWhere( | ||||
|                 $qb->expr()->gt( | ||||
|                     'SIZE(p.accompanyingPeriodParticipations)', | ||||
|                     0 | ||||
|                 ) | ||||
|             ) | ||||
|             ->andWhere( | ||||
|                 $qb->expr()->eq('ap.step', ':step') | ||||
|             ) | ||||
|             ->setParameter('center', $center) | ||||
|             ->setParameter('step', AccompanyingPeriod::STEP_CONFIRMED) | ||||
|             ->setMaxResults($maxResults) | ||||
|             ->getQuery() | ||||
|             ->getScalarResult(); | ||||
|  | ||||
|         // create a random order | ||||
|         shuffle($personIds); | ||||
|  | ||||
|         $socialIssues = $em->createQuery('SELECT s FROM '. | ||||
|             SocialIssue::class.' s ') | ||||
|             ->setMaxResults(10) | ||||
|             ->getResult(); | ||||
|  | ||||
|         $nbGenerated = 0; | ||||
|  | ||||
|         while ($nbGenerated < $maxGenerated) { | ||||
|             $id = \array_pop($personIds)['id']; | ||||
|  | ||||
|             $person = $em->getRepository(Person::class) | ||||
|                 ->find($id); | ||||
|             $periods = $person->getAccompanyingPeriods(); | ||||
|  | ||||
|             yield [$periods[\array_rand($periods)], $socialIssues[\array_rand($socialIssues)]]; | ||||
|  | ||||
|             ++$nbGenerated; | ||||
|         } | ||||
|  | ||||
|         self::ensureKernelShutdown(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider dataGenerateRandomAccompanyingCourse | ||||
|      */ | ||||
| @@ -525,6 +352,43 @@ final class AccompanyingCourseApiControllerTest extends WebTestCase | ||||
|         $this->period = $period; | ||||
|     } | ||||
|  | ||||
|     public static function dataGenerateNewAccompanyingCourse() | ||||
|     { | ||||
|         self::bootKernel(); | ||||
|         $em = self::getContainer()->get(EntityManagerInterface::class); | ||||
|  | ||||
|         $period = new AccompanyingPeriod(new \DateTime('1 week ago')); | ||||
|         $user = $em->getRepository(User::class) | ||||
|             ->findOneByUsernameCanonical('center a_social'); | ||||
|         $period->setCreatedBy($user); | ||||
|         // $period->setCreatedAt(new \DateTime('yesterday')); | ||||
|  | ||||
|         $center = $em->getRepository(Center::class) | ||||
|             ->findOneBy(['name' => 'Center A']); | ||||
|  | ||||
|         $personIds = $em->createQuery('SELECT p.id FROM '. | ||||
|             Person::class.' p JOIN p.centerCurrent cc'. | ||||
|             ' WHERE cc.center = :center') | ||||
|             ->setParameter('center', $center) | ||||
|             ->setMaxResults(100) | ||||
|             ->getScalarResult(); | ||||
|  | ||||
|         // create a random order | ||||
|         shuffle($personIds); | ||||
|  | ||||
|         for ($i = 0; 2 > $i; ++$i) { | ||||
|             $person = $em->getRepository(Person::class)->find(\array_pop($personIds)); | ||||
|             $period->addPerson($person); | ||||
|         } | ||||
|  | ||||
|         $em->persist($period); | ||||
|         $em->flush(); | ||||
|  | ||||
|         yield [$period]; | ||||
|  | ||||
|         self::ensureKernelShutdown(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider dataGenerateRandomAccompanyingCourse | ||||
|      */ | ||||
| @@ -539,6 +403,73 @@ final class AccompanyingCourseApiControllerTest extends WebTestCase | ||||
|         $this->assertTrue(\in_array($client->getResponse()->getStatusCode(), [200, 422], true)); | ||||
|     } | ||||
|  | ||||
|     public static function dataGenerateRandomAccompanyingCourse() | ||||
|     { | ||||
|         // note about max result for person query, and maxGenerated: | ||||
|         // | ||||
|         // in the final loop, an id is popped out of the personIds array twice: | ||||
|         // | ||||
|         // * one for getting the person, which will in turn provide his accompanying period; | ||||
|         // * one for getting the personId to populate to the data manager | ||||
|         // | ||||
|         // Ensure to keep always $maxGenerated to the double of $maxResults. x8 is a good compromize :) | ||||
|         $maxGenerated = 3; | ||||
|         $maxResults = $maxGenerated * 8; | ||||
|  | ||||
|         self::bootKernel(); | ||||
|         $em = self::getContainer()->get(EntityManagerInterface::class); | ||||
|         $center = $em->getRepository(Center::class) | ||||
|             ->findOneBy(['name' => 'Center A']); | ||||
|  | ||||
|         $qb = $em->createQueryBuilder(); | ||||
|         $personIds = $qb | ||||
|             ->select('p.id') | ||||
|             ->distinct(true) | ||||
|             ->from(Person::class, 'p') | ||||
|             ->join('p.accompanyingPeriodParticipations', 'participation') | ||||
|             ->join('participation.accompanyingPeriod', 'ap') | ||||
|             ->join('p.centerCurrent', 'cc') | ||||
|             ->where( | ||||
|                 $qb->expr()->eq( | ||||
|                     'cc.center', | ||||
|                     ':center' | ||||
|                 ) | ||||
|             ) | ||||
|             ->andWhere( | ||||
|                 $qb->expr()->gt( | ||||
|                     'SIZE(p.accompanyingPeriodParticipations)', | ||||
|                     0 | ||||
|                 ) | ||||
|             ) | ||||
|             ->andWhere( | ||||
|                 $qb->expr()->eq('ap.step', ':step') | ||||
|             ) | ||||
|             ->setParameter('center', $center) | ||||
|             ->setParameter('step', AccompanyingPeriod::STEP_CONFIRMED) | ||||
|             ->setMaxResults($maxResults) | ||||
|             ->getQuery() | ||||
|             ->getScalarResult(); | ||||
|  | ||||
|         // create a random order | ||||
|         shuffle($personIds); | ||||
|  | ||||
|         $nbGenerated = 0; | ||||
|  | ||||
|         while ($nbGenerated < $maxGenerated) { | ||||
|             $id = \array_pop($personIds)['id']; | ||||
|  | ||||
|             $person = $em->getRepository(Person::class) | ||||
|                 ->find($id); | ||||
|             $periods = $person->getAccompanyingPeriods(); | ||||
|  | ||||
|             yield [\array_pop($personIds)['id'], $periods[\array_rand($periods)]->getId()]; | ||||
|  | ||||
|             ++$nbGenerated; | ||||
|         } | ||||
|  | ||||
|         self::ensureKernelShutdown(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider dataGenerateRandomRequestorValidData | ||||
|      */ | ||||
| @@ -713,6 +644,75 @@ final class AccompanyingCourseApiControllerTest extends WebTestCase | ||||
|         $this->assertTrue(\in_array($response->getStatusCode(), [200, 422], true)); | ||||
|     } | ||||
|  | ||||
|     public static function dataGenerateRandomRequestorValidData(): \Iterator | ||||
|     { | ||||
|         $dataLength = 2; | ||||
|         $maxResults = 100; | ||||
|  | ||||
|         self::bootKernel(); | ||||
|         $em = self::getContainer()->get(EntityManagerInterface::class); | ||||
|         $center = $em->getRepository(Center::class) | ||||
|             ->findOneBy(['name' => 'Center A']); | ||||
|         $qb = $em->createQueryBuilder(); | ||||
|  | ||||
|         $personIds = $qb | ||||
|             ->select('p.id') | ||||
|             ->distinct(true) | ||||
|             ->from(Person::class, 'p') | ||||
|             ->join('p.accompanyingPeriodParticipations', 'participation') | ||||
|             ->join('participation.accompanyingPeriod', 'ap') | ||||
|             ->join('p.centerCurrent', 'cc') | ||||
|             ->where( | ||||
|                 $qb->expr()->eq( | ||||
|                     'cc.center', | ||||
|                     ':center' | ||||
|                 ) | ||||
|             ) | ||||
|             ->andWhere( | ||||
|                 $qb->expr()->gt( | ||||
|                     'SIZE(p.accompanyingPeriodParticipations)', | ||||
|                     0 | ||||
|                 ) | ||||
|             ) | ||||
|             ->andWhere( | ||||
|                 $qb->expr()->eq('ap.step', ':step') | ||||
|             ) | ||||
|             ->setParameter('center', $center) | ||||
|             ->setParameter('step', AccompanyingPeriod::STEP_CONFIRMED) | ||||
|             ->setMaxResults($maxResults) | ||||
|             ->getQuery() | ||||
|             ->getScalarResult(); | ||||
|  | ||||
|         // create a random order | ||||
|         shuffle($personIds); | ||||
|  | ||||
|         $thirdPartyIds = $em->createQuery('SELECT t.id FROM '. | ||||
|             ThirdParty::class.' t ') | ||||
|             ->setMaxResults($maxResults) | ||||
|             ->getScalarResult(); | ||||
|  | ||||
|         // create a random order | ||||
|         shuffle($thirdPartyIds); | ||||
|  | ||||
|         $i = 0; | ||||
|  | ||||
|         while ($i <= $dataLength) { | ||||
|             $person = $em->getRepository(Person::class) | ||||
|                 ->find(\array_pop($personIds)['id']); | ||||
|  | ||||
|             if (0 === \count($person->getAccompanyingPeriods())) { | ||||
|                 continue; | ||||
|             } | ||||
|  | ||||
|             $period = $person->getAccompanyingPeriods()[0]; | ||||
|  | ||||
|             yield [$period, \array_pop($personIds)['id'], \array_pop($thirdPartyIds)['id']]; | ||||
|             ++$i; | ||||
|         } | ||||
|  | ||||
|         self::ensureKernelShutdown(); | ||||
|     } | ||||
|  | ||||
|     public function testShow404() | ||||
|     { | ||||
|         $client = $this->getClientAuthenticated(); | ||||
|   | ||||
| @@ -41,32 +41,6 @@ final class AccompanyingCourseControllerTest extends WebTestCase | ||||
|         self::ensureKernelShutdown(); | ||||
|     } | ||||
|  | ||||
|     public static function dataGenerateRandomUsers(): \Iterator | ||||
|     { | ||||
|         self::bootKernel(); | ||||
|         $em = self::getContainer()->get(EntityManagerInterface::class); | ||||
|  | ||||
|         $period = new AccompanyingPeriod(new \DateTime('1 week ago')); | ||||
|         $user = $em->getRepository(User::class) | ||||
|             ->findOneByUsernameCanonical('center a_social'); | ||||
|         $period->setCreatedBy($user); | ||||
|         // $period->setCreatedAt(new \DateTime('yesterday')); | ||||
|  | ||||
|         $center = $em->getRepository(Center::class) | ||||
|             ->findOneBy(['name' => 'Center A']); | ||||
|  | ||||
|         $personIds = $em->createQuery('SELECT p.id FROM '. | ||||
|             Person::class.' p JOIN p.centerCurrent cc '. | ||||
|             ' WHERE cc.center = :center') | ||||
|             ->setParameter('center', $center) | ||||
|             ->setMaxResults(100) | ||||
|             ->getScalarResult(); | ||||
|  | ||||
|         yield [\array_pop($personIds), \array_pop($personIds)]; | ||||
|  | ||||
|         self::ensureKernelShutdown(); | ||||
|     } | ||||
|  | ||||
|     public function testNewWithoutUsers() | ||||
|     { | ||||
|         $this->client->request('GET', '/fr/person/parcours/new'); | ||||
| @@ -104,4 +78,30 @@ final class AccompanyingCourseControllerTest extends WebTestCase | ||||
|  | ||||
|         $this->assertEquals(2, \count($period->getParticipations())); | ||||
|     } | ||||
|  | ||||
|     public static function dataGenerateRandomUsers(): \Iterator | ||||
|     { | ||||
|         self::bootKernel(); | ||||
|         $em = self::getContainer()->get(EntityManagerInterface::class); | ||||
|  | ||||
|         $period = new AccompanyingPeriod(new \DateTime('1 week ago')); | ||||
|         $user = $em->getRepository(User::class) | ||||
|             ->findOneByUsernameCanonical('center a_social'); | ||||
|         $period->setCreatedBy($user); | ||||
|         // $period->setCreatedAt(new \DateTime('yesterday')); | ||||
|  | ||||
|         $center = $em->getRepository(Center::class) | ||||
|             ->findOneBy(['name' => 'Center A']); | ||||
|  | ||||
|         $personIds = $em->createQuery('SELECT p.id FROM '. | ||||
|             Person::class.' p JOIN p.centerCurrent cc '. | ||||
|             ' WHERE cc.center = :center') | ||||
|             ->setParameter('center', $center) | ||||
|             ->setMaxResults(100) | ||||
|             ->getScalarResult(); | ||||
|  | ||||
|         yield [\array_pop($personIds), \array_pop($personIds)]; | ||||
|  | ||||
|         self::ensureKernelShutdown(); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -37,6 +37,28 @@ final class HouseholdApiControllerTest extends WebTestCase | ||||
|  | ||||
|     private static array $toDelete = []; | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider generateHouseholdAssociatedWithAddressReference | ||||
|      */ | ||||
|     public function testFindHouseholdByAddressReference(int $addressReferenceId, int $expectedHouseholdId) | ||||
|     { | ||||
|         $client = $this->getClientAuthenticated(); | ||||
|  | ||||
|         $client->request( | ||||
|             Request::METHOD_GET, | ||||
|             "/api/1.0/person/household/by-address-reference/{$addressReferenceId}.json" | ||||
|         ); | ||||
|  | ||||
|         $this->assertResponseIsSuccessful(); | ||||
|         $data = json_decode($client->getResponse()->getContent(), true, 512, JSON_THROW_ON_ERROR); | ||||
|         $this->assertArrayHasKey('count', $data); | ||||
|         $this->assertArrayHasKey('results', $data); | ||||
|  | ||||
|         $householdIds = \array_map(static fn ($r) => $r['id'], $data['results']); | ||||
|  | ||||
|         $this->assertContains($expectedHouseholdId, $householdIds); | ||||
|     } | ||||
|  | ||||
|     public static function generateHouseholdAssociatedWithAddressReference() | ||||
|     { | ||||
|         self::bootKernel(); | ||||
| @@ -86,6 +108,21 @@ final class HouseholdApiControllerTest extends WebTestCase | ||||
|         self::ensureKernelShutdown(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider generateHouseholdId | ||||
|      */ | ||||
|     public function testSuggestAddressByHousehold(int $householdId) | ||||
|     { | ||||
|         $client = $this->getClientAuthenticated(); | ||||
|  | ||||
|         $client->request( | ||||
|             Request::METHOD_GET, | ||||
|             "/api/1.0/person/address/suggest/by-household/{$householdId}.json" | ||||
|         ); | ||||
|  | ||||
|         $this->assertResponseIsSuccessful(); | ||||
|     } | ||||
|  | ||||
|     public static function generateHouseholdId() | ||||
|     { | ||||
|         self::bootKernel(); | ||||
| @@ -118,6 +155,21 @@ final class HouseholdApiControllerTest extends WebTestCase | ||||
|         self::ensureKernelShutdown(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider generatePersonId | ||||
|      */ | ||||
|     public function testSuggestByAccompanyingPeriodParticipation(int $personId) | ||||
|     { | ||||
|         $client = $this->getClientAuthenticated(); | ||||
|  | ||||
|         $client->request( | ||||
|             Request::METHOD_GET, | ||||
|             "/api/1.0/person/household/suggest/by-person/{$personId}/through-accompanying-period-participation.json" | ||||
|         ); | ||||
|  | ||||
|         $this->assertResponseIsSuccessful(); | ||||
|     } | ||||
|  | ||||
|     public static function generatePersonId() | ||||
|     { | ||||
|         self::bootKernel(); | ||||
| @@ -139,56 +191,4 @@ final class HouseholdApiControllerTest extends WebTestCase | ||||
|  | ||||
|         self::ensureKernelShutdown(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider generateHouseholdAssociatedWithAddressReference | ||||
|      */ | ||||
|     public function testFindHouseholdByAddressReference(int $addressReferenceId, int $expectedHouseholdId) | ||||
|     { | ||||
|         $client = $this->getClientAuthenticated(); | ||||
|  | ||||
|         $client->request( | ||||
|             Request::METHOD_GET, | ||||
|             "/api/1.0/person/household/by-address-reference/{$addressReferenceId}.json" | ||||
|         ); | ||||
|  | ||||
|         $this->assertResponseIsSuccessful(); | ||||
|         $data = json_decode($client->getResponse()->getContent(), true, 512, JSON_THROW_ON_ERROR); | ||||
|         $this->assertArrayHasKey('count', $data); | ||||
|         $this->assertArrayHasKey('results', $data); | ||||
|  | ||||
|         $householdIds = \array_map(static fn ($r) => $r['id'], $data['results']); | ||||
|  | ||||
|         $this->assertContains($expectedHouseholdId, $householdIds); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider generateHouseholdId | ||||
|      */ | ||||
|     public function testSuggestAddressByHousehold(int $householdId) | ||||
|     { | ||||
|         $client = $this->getClientAuthenticated(); | ||||
|  | ||||
|         $client->request( | ||||
|             Request::METHOD_GET, | ||||
|             "/api/1.0/person/address/suggest/by-household/{$householdId}.json" | ||||
|         ); | ||||
|  | ||||
|         $this->assertResponseIsSuccessful(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider generatePersonId | ||||
|      */ | ||||
|     public function testSuggestByAccompanyingPeriodParticipation(int $personId) | ||||
|     { | ||||
|         $client = $this->getClientAuthenticated(); | ||||
|  | ||||
|         $client->request( | ||||
|             Request::METHOD_GET, | ||||
|             "/api/1.0/person/household/suggest/by-person/{$personId}/through-accompanying-period-participation.json" | ||||
|         ); | ||||
|  | ||||
|         $this->assertResponseIsSuccessful(); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -39,33 +39,6 @@ final class HouseholdControllerTest extends WebTestCase | ||||
|         self::ensureKernelShutdown(); | ||||
|     } | ||||
|  | ||||
|     public static function generateValidHouseholdIds() | ||||
|     { | ||||
|         self::bootKernel(); | ||||
|         $em = self::getContainer()->get(EntityManagerInterface::class); | ||||
|  | ||||
|         $ids = $em->createQuery( | ||||
|             sprintf('SELECT DISTINCT h.id FROM %s h JOIN h.members m JOIN m.person p JOIN p.centerHistory ch JOIN ch.center c WHERE c.name = :center AND ch.endDate IS NULL', Household::class) | ||||
|         ) | ||||
|             ->setParameter('center', 'Center A') | ||||
|             ->setMaxResults(100) | ||||
|             ->getScalarResult(); | ||||
|  | ||||
|         if ([] === $ids) { | ||||
|             throw new \RuntimeException('no household ids with center "Center A"'); | ||||
|         } | ||||
|  | ||||
|         \shuffle($ids); | ||||
|  | ||||
|         yield [\array_pop($ids)['id']]; | ||||
|  | ||||
|         yield [\array_pop($ids)['id']]; | ||||
|  | ||||
|         yield [\array_pop($ids)['id']]; | ||||
|  | ||||
|         self::ensureKernelShutdown(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider generateValidHouseholdIds | ||||
|      */ | ||||
| @@ -136,4 +109,31 @@ final class HouseholdControllerTest extends WebTestCase | ||||
|  | ||||
|         $this->assertResponseIsSuccessful(); | ||||
|     } | ||||
|  | ||||
|     public static function generateValidHouseholdIds() | ||||
|     { | ||||
|         self::bootKernel(); | ||||
|         $em = self::getContainer()->get(EntityManagerInterface::class); | ||||
|  | ||||
|         $ids = $em->createQuery( | ||||
|             sprintf('SELECT DISTINCT h.id FROM %s h JOIN h.members m JOIN m.person p JOIN p.centerHistory ch JOIN ch.center c WHERE c.name = :center AND ch.endDate IS NULL', Household::class) | ||||
|         ) | ||||
|             ->setParameter('center', 'Center A') | ||||
|             ->setMaxResults(100) | ||||
|             ->getScalarResult(); | ||||
|  | ||||
|         if ([] === $ids) { | ||||
|             throw new \RuntimeException('no household ids with center "Center A"'); | ||||
|         } | ||||
|  | ||||
|         \shuffle($ids); | ||||
|  | ||||
|         yield [\array_pop($ids)['id']]; | ||||
|  | ||||
|         yield [\array_pop($ids)['id']]; | ||||
|  | ||||
|         yield [\array_pop($ids)['id']]; | ||||
|  | ||||
|         self::ensureKernelShutdown(); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -30,78 +30,6 @@ final class HouseholdMemberControllerTest extends WebTestCase | ||||
| { | ||||
|     use PrepareClientTrait; | ||||
|  | ||||
|     public static function provideValidDataEditMember(): \Iterator | ||||
|     { | ||||
|         self::bootKernel(); | ||||
|         $em = self::getContainer()->get(EntityManagerInterface::class); | ||||
|  | ||||
|         $membershipIds = $em->createQuery(sprintf('SELECT m.id FROM %s m JOIN m.person p JOIN p.centerHistory ch JOIN ch.center c WHERE c.name = :center AND m.endDate IS NULL AND ch.endDate IS NULL', HouseholdMember::class)) | ||||
|             ->setParameter('center', 'Center A') | ||||
|             ->getScalarResult(); | ||||
|  | ||||
|         if ([] === $membershipIds) { | ||||
|             throw new \RuntimeException("no memberships for person associated to 'Center A'"); | ||||
|         } | ||||
|  | ||||
|         \shuffle($membershipIds); | ||||
|  | ||||
|         yield [\array_pop($membershipIds)['id']]; | ||||
|     } | ||||
|  | ||||
|     public static function provideValidDataMove(): \Iterator | ||||
|     { | ||||
|         self::bootKernel(); | ||||
|         $em = self::getContainer()->get(EntityManagerInterface::class); | ||||
|         $yesterday = new \DateTimeImmutable('yesterday'); | ||||
|  | ||||
|         $personIds = $em->createQuery( | ||||
|             sprintf('SELECT p.id FROM %s p JOIN p.centerHistory ch JOIN ch.center c WHERE c.name = :center AND ch.endDate IS NULL', Person::class) | ||||
|         ) | ||||
|             ->setParameter('center', 'Center A') | ||||
|             ->setMaxResults(100) | ||||
|             ->getScalarResult(); | ||||
|  | ||||
|         if ([] === $personIds) { | ||||
|             throw new \RuntimeException('no person associated with "Center A"'); | ||||
|         } | ||||
|  | ||||
|         \shuffle($personIds); | ||||
|  | ||||
|         $household = new Household(); | ||||
|         $em->persist($household); | ||||
|         $em->flush(); | ||||
|  | ||||
|         $positions = $em->createQuery('SELECT pos.id FROM '.Position::class.' pos '. | ||||
|             'WHERE pos.shareHouseHold = TRUE') | ||||
|             ->getResult(); | ||||
|  | ||||
|         $i = 0; | ||||
|  | ||||
|         do { | ||||
|             $id = \array_pop($personIds)['id']; | ||||
|             $person = self::getContainer()->get(EntityManagerInterface::class) | ||||
|                 ->getRepository(Person::class) | ||||
|                 ->find($id); | ||||
|  | ||||
|             $participation = $person->getCurrentHouseholdParticipationShareHousehold(); | ||||
|  | ||||
|             if (null === $participation | ||||
|                 || ( | ||||
|                     null === $participation->getEndDate() | ||||
|                     && $participation->getStartDate() <= $yesterday | ||||
|                 )) { | ||||
|                 ++$i; | ||||
|  | ||||
|                 yield [ | ||||
|                     $id, | ||||
|                     $household->getId(), | ||||
|                     $positions[\random_int(0, \count($positions) - 1)]['id'], | ||||
|                     new \DateTimeImmutable('tomorrow'), | ||||
|                 ]; | ||||
|             } | ||||
|         } while (1 >= $i); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider provideValidDataEditMember | ||||
|      */ | ||||
| @@ -124,6 +52,24 @@ final class HouseholdMemberControllerTest extends WebTestCase | ||||
|         $this->assertEquals(302, $client->getResponse()->getStatusCode()); | ||||
|     } | ||||
|  | ||||
|     public static function provideValidDataEditMember(): \Iterator | ||||
|     { | ||||
|         self::bootKernel(); | ||||
|         $em = self::getContainer()->get(EntityManagerInterface::class); | ||||
|  | ||||
|         $membershipIds = $em->createQuery(sprintf('SELECT m.id FROM %s m JOIN m.person p JOIN p.centerHistory ch JOIN ch.center c WHERE c.name = :center AND m.endDate IS NULL AND ch.endDate IS NULL', HouseholdMember::class)) | ||||
|             ->setParameter('center', 'Center A') | ||||
|             ->getScalarResult(); | ||||
|  | ||||
|         if ([] === $membershipIds) { | ||||
|             throw new \RuntimeException("no memberships for person associated to 'Center A'"); | ||||
|         } | ||||
|  | ||||
|         \shuffle($membershipIds); | ||||
|  | ||||
|         yield [\array_pop($membershipIds)['id']]; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider provideValidDataMove | ||||
|      */ | ||||
| @@ -278,4 +224,58 @@ final class HouseholdMemberControllerTest extends WebTestCase | ||||
|         $this->assertArrayHasKey('id', $data['members'][0]['person']); | ||||
|         $this->assertEquals($personId, $data['members'][0]['person']['id']); | ||||
|     } | ||||
|  | ||||
|     public static function provideValidDataMove(): \Iterator | ||||
|     { | ||||
|         self::bootKernel(); | ||||
|         $em = self::getContainer()->get(EntityManagerInterface::class); | ||||
|         $yesterday = new \DateTimeImmutable('yesterday'); | ||||
|  | ||||
|         $personIds = $em->createQuery( | ||||
|             sprintf('SELECT p.id FROM %s p JOIN p.centerHistory ch JOIN ch.center c WHERE c.name = :center AND ch.endDate IS NULL', Person::class) | ||||
|         ) | ||||
|             ->setParameter('center', 'Center A') | ||||
|             ->setMaxResults(100) | ||||
|             ->getScalarResult(); | ||||
|  | ||||
|         if ([] === $personIds) { | ||||
|             throw new \RuntimeException('no person associated with "Center A"'); | ||||
|         } | ||||
|  | ||||
|         \shuffle($personIds); | ||||
|  | ||||
|         $household = new Household(); | ||||
|         $em->persist($household); | ||||
|         $em->flush(); | ||||
|  | ||||
|         $positions = $em->createQuery('SELECT pos.id FROM '.Position::class.' pos '. | ||||
|             'WHERE pos.shareHouseHold = TRUE') | ||||
|             ->getResult(); | ||||
|  | ||||
|         $i = 0; | ||||
|  | ||||
|         do { | ||||
|             $id = \array_pop($personIds)['id']; | ||||
|             $person = self::getContainer()->get(EntityManagerInterface::class) | ||||
|                 ->getRepository(Person::class) | ||||
|                 ->find($id); | ||||
|  | ||||
|             $participation = $person->getCurrentHouseholdParticipationShareHousehold(); | ||||
|  | ||||
|             if (null === $participation | ||||
|                 || ( | ||||
|                     null === $participation->getEndDate() | ||||
|                     && $participation->getStartDate() <= $yesterday | ||||
|                 )) { | ||||
|                 ++$i; | ||||
|  | ||||
|                 yield [ | ||||
|                     $id, | ||||
|                     $household->getId(), | ||||
|                     $positions[\random_int(0, \count($positions) - 1)]['id'], | ||||
|                     new \DateTimeImmutable('tomorrow'), | ||||
|                 ]; | ||||
|             } | ||||
|         } while (1 >= $i); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -26,47 +26,6 @@ final class PersonApiControllerTest extends WebTestCase | ||||
| { | ||||
|     use PrepareClientTrait; | ||||
|  | ||||
|     public static function dataGetPersonFromCenterA(): \Iterator | ||||
|     { | ||||
|         self::bootKernel(); | ||||
|         $em = self::getContainer()->get(EntityManagerInterface::class); | ||||
|         $personIds = $em->createQuery(sprintf( | ||||
|             'SELECT p.id FROM %s p JOIN p.centerCurrent pc JOIN pc.center c WHERE c.name = :center', | ||||
|             Person::class | ||||
|         )) | ||||
|             ->setParameter('center', 'Center A') | ||||
|             ->setMaxResults(100) | ||||
|             ->getScalarResult(); | ||||
|  | ||||
|         \shuffle($personIds); | ||||
|  | ||||
|         yield \array_pop($personIds); | ||||
|  | ||||
|         yield \array_pop($personIds); | ||||
|  | ||||
|         yield \array_pop($personIds); | ||||
|  | ||||
|         yield \array_pop($personIds); | ||||
|     } | ||||
|  | ||||
|     public static function dataGetPersonFromCenterB(): \Iterator | ||||
|     { | ||||
|         self::bootKernel(); | ||||
|         $em = self::getContainer()->get(EntityManagerInterface::class); | ||||
|         $personIds = $em->createQuery( | ||||
|             sprintf('SELECT p.id FROM %s p JOIN p.centerCurrent pc JOIN pc.center c WHERE c.name = :center', Person::class) | ||||
|         ) | ||||
|             ->setParameter('center', 'Center B') | ||||
|             ->setMaxResults(100) | ||||
|             ->getScalarResult(); | ||||
|  | ||||
|         \shuffle($personIds); | ||||
|  | ||||
|         yield \array_pop($personIds); | ||||
|  | ||||
|         yield \array_pop($personIds); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider dataGetPersonFromCenterA | ||||
|      */ | ||||
| @@ -112,6 +71,29 @@ final class PersonApiControllerTest extends WebTestCase | ||||
|         $this->assertEquals($personId, $data['id']); | ||||
|     } | ||||
|  | ||||
|     public static function dataGetPersonFromCenterA(): \Iterator | ||||
|     { | ||||
|         self::bootKernel(); | ||||
|         $em = self::getContainer()->get(EntityManagerInterface::class); | ||||
|         $personIds = $em->createQuery(sprintf( | ||||
|             'SELECT p.id FROM %s p JOIN p.centerCurrent pc JOIN pc.center c WHERE c.name = :center', | ||||
|             Person::class | ||||
|         )) | ||||
|             ->setParameter('center', 'Center A') | ||||
|             ->setMaxResults(100) | ||||
|             ->getScalarResult(); | ||||
|  | ||||
|         \shuffle($personIds); | ||||
|  | ||||
|         yield \array_pop($personIds); | ||||
|  | ||||
|         yield \array_pop($personIds); | ||||
|  | ||||
|         yield \array_pop($personIds); | ||||
|  | ||||
|         yield \array_pop($personIds); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider dataGetPersonFromCenterB | ||||
|      */ | ||||
| @@ -124,4 +106,22 @@ final class PersonApiControllerTest extends WebTestCase | ||||
|  | ||||
|         $this->assertEquals(403, $response->getStatusCode()); | ||||
|     } | ||||
|  | ||||
|     public static function dataGetPersonFromCenterB(): \Iterator | ||||
|     { | ||||
|         self::bootKernel(); | ||||
|         $em = self::getContainer()->get(EntityManagerInterface::class); | ||||
|         $personIds = $em->createQuery( | ||||
|             sprintf('SELECT p.id FROM %s p JOIN p.centerCurrent pc JOIN pc.center c WHERE c.name = :center', Person::class) | ||||
|         ) | ||||
|             ->setParameter('center', 'Center B') | ||||
|             ->setMaxResults(100) | ||||
|             ->getScalarResult(); | ||||
|  | ||||
|         \shuffle($personIds); | ||||
|  | ||||
|         yield \array_pop($personIds); | ||||
|  | ||||
|         yield \array_pop($personIds); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -164,24 +164,6 @@ final class PersonControllerUpdateWithHiddenFieldsTest extends WebTestCase | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Test the configurable fields are absent. | ||||
|      * | ||||
|      * @group configurable_fields | ||||
|      */ | ||||
|     public function testHiddenFielsAreAbsent() | ||||
|     { | ||||
|         $crawler = $this->client->request('GET', $this->editUrl); | ||||
|  | ||||
|         $configurables = ['placeOfBirth', 'phonenumber', 'email', | ||||
|             'countryOfBirth', 'nationality', 'spokenLanguages', 'maritalStatus', ]; | ||||
|         $form = $crawler->selectButton('Submit')->form(); // ; | ||||
|  | ||||
|         foreach ($configurables as $key) { | ||||
|             $this->assertFalse($form->has('chill_personbundle_person['.$key.']')); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * provide valid values to test, with field name and | ||||
|      * a function to find the value back from person entity. | ||||
| @@ -200,6 +182,24 @@ final class PersonControllerUpdateWithHiddenFieldsTest extends WebTestCase | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Test the configurable fields are absent. | ||||
|      * | ||||
|      * @group configurable_fields | ||||
|      */ | ||||
|     public function testHiddenFielsAreAbsent() | ||||
|     { | ||||
|         $crawler = $this->client->request('GET', $this->editUrl); | ||||
|  | ||||
|         $configurables = ['placeOfBirth', 'phonenumber', 'email', | ||||
|             'countryOfBirth', 'nationality', 'spokenLanguages', 'maritalStatus', ]; | ||||
|         $form = $crawler->selectButton('Submit')->form(); // ; | ||||
|  | ||||
|         foreach ($configurables as $key) { | ||||
|             $this->assertFalse($form->has('chill_personbundle_person['.$key.']')); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Reload the person from the db. | ||||
|      */ | ||||
|   | ||||
| @@ -23,6 +23,38 @@ use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; | ||||
|  */ | ||||
| final class PersonDuplicateControllerViewTest extends WebTestCase | ||||
| { | ||||
|     /** | ||||
|      * @dataProvider providePersonData | ||||
|      */ | ||||
|     public function testViewDuplicatePerson(int $personId, int $person2Id): void | ||||
|     { | ||||
|         $client = self::createClient([], [ | ||||
|             'PHP_AUTH_USER' => 'center a_social', | ||||
|             'PHP_AUTH_PW' => 'password', | ||||
|         ]); | ||||
|  | ||||
|         $crawler = $client->request('GET', '/en/person/'.$personId.'/duplicate/view'); | ||||
|         $response = $client->getResponse(); | ||||
|         $this->assertTrue($response->isSuccessful()); | ||||
|  | ||||
|         $this->assertGreaterThan(0, $crawler->filter('html:contains("Find duplicate")')->count()); | ||||
|         $this->assertGreaterThan(0, $crawler->filter('html:contains("Réginal")')->count()); | ||||
|         $this->assertGreaterThan(0, $crawler->filter('html:contains("Réginald")')->count()); | ||||
|  | ||||
|         $crawler = $client->request('GET', '/en/person/'.$personId.'/duplicate/'.$person2Id.'/confirm'); | ||||
|         $response = $client->getResponse(); | ||||
|         $this->assertTrue($response->isSuccessful()); | ||||
|  | ||||
|         $this->assertGreaterThan(0, $crawler->filter('html:contains("Old person")')->count()); | ||||
|         $this->assertGreaterThan(0, $crawler->filter('html:contains("New person")')->count()); | ||||
|  | ||||
|         $crawler = $client->request('POST', '/en/person/'.$personId.'/duplicate/'.$person2Id.'/confirm', [ | ||||
|             'chill_personbundle_person_confirm_duplicate[confirm]' => 1, | ||||
|         ]); | ||||
|         $response = $client->getResponse(); | ||||
|         $this->assertTrue($response->isSuccessful()); | ||||
|     } | ||||
|  | ||||
|     public static function providePersonData(): iterable | ||||
|     { | ||||
|         self::bootKernel(); | ||||
| @@ -60,36 +92,4 @@ final class PersonDuplicateControllerViewTest extends WebTestCase | ||||
|  | ||||
|         yield [$person->getId(), $person2->getId()]; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider providePersonData | ||||
|      */ | ||||
|     public function testViewDuplicatePerson(int $personId, int $person2Id): void | ||||
|     { | ||||
|         $client = self::createClient([], [ | ||||
|             'PHP_AUTH_USER' => 'center a_social', | ||||
|             'PHP_AUTH_PW' => 'password', | ||||
|         ]); | ||||
|  | ||||
|         $crawler = $client->request('GET', '/en/person/'.$personId.'/duplicate/view'); | ||||
|         $response = $client->getResponse(); | ||||
|         $this->assertTrue($response->isSuccessful()); | ||||
|  | ||||
|         $this->assertGreaterThan(0, $crawler->filter('html:contains("Find duplicate")')->count()); | ||||
|         $this->assertGreaterThan(0, $crawler->filter('html:contains("Réginal")')->count()); | ||||
|         $this->assertGreaterThan(0, $crawler->filter('html:contains("Réginald")')->count()); | ||||
|  | ||||
|         $crawler = $client->request('GET', '/en/person/'.$personId.'/duplicate/'.$person2Id.'/confirm'); | ||||
|         $response = $client->getResponse(); | ||||
|         $this->assertTrue($response->isSuccessful()); | ||||
|  | ||||
|         $this->assertGreaterThan(0, $crawler->filter('html:contains("Old person")')->count()); | ||||
|         $this->assertGreaterThan(0, $crawler->filter('html:contains("New person")')->count()); | ||||
|  | ||||
|         $crawler = $client->request('POST', '/en/person/'.$personId.'/duplicate/'.$person2Id.'/confirm', [ | ||||
|             'chill_personbundle_person_confirm_duplicate[confirm]' => 1, | ||||
|         ]); | ||||
|         $response = $client->getResponse(); | ||||
|         $this->assertTrue($response->isSuccessful()); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -40,6 +40,19 @@ final class RelationshipApiControllerTest extends WebTestCase | ||||
|         self::ensureKernelShutdown(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider personProvider | ||||
|      */ | ||||
|     public function testGetRelationshipByPerson(int $personId) | ||||
|     { | ||||
|         self::ensureKernelShutdown(); | ||||
|         $client = $this->getClientAuthenticated(); | ||||
|         $client->request(Request::METHOD_GET, sprintf('/api/1.0/relations/relationship/by-person/%d.json', $personId)); | ||||
|  | ||||
|         $response = $client->getResponse(); | ||||
|         $this->assertEquals(200, $response->getStatusCode(), 'Test to see that API response returns a status code 200'); | ||||
|     } | ||||
|  | ||||
|     public static function personProvider(): array | ||||
|     { | ||||
|         self::bootKernel(); | ||||
| @@ -75,42 +88,6 @@ final class RelationshipApiControllerTest extends WebTestCase | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|     public static function relationProvider(): array | ||||
|     { | ||||
|         self::bootKernel(); | ||||
|         $em = self::getContainer()->get(EntityManagerInterface::class); | ||||
|         $personIdWithoutRelations = $em->createQueryBuilder() | ||||
|             ->select('p.id') | ||||
|             ->from(Person::class, 'p') | ||||
|             ->join('p.centerCurrent', 'center_current') | ||||
|             ->join('center_current.center', 'c') | ||||
|             ->where('c.name LIKE :name') | ||||
|             ->andWhere('NOT EXISTS (SELECT 1 FROM '.Relationship::class.' r WHERE r.fromPerson = p OR r.toPerson = p)') | ||||
|             ->setParameter('name', 'Center A') | ||||
|             ->getQuery() | ||||
|             ->setMaxResults(2) | ||||
|             ->getResult(); | ||||
|  | ||||
|         self::ensureKernelShutdown(); | ||||
|  | ||||
|         return [ | ||||
|             [$personIdWithoutRelations[0]['id'], $personIdWithoutRelations[1]['id'], self::getRandomRelation($em)->getId(), true], | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider personProvider | ||||
|      */ | ||||
|     public function testGetRelationshipByPerson(int $personId) | ||||
|     { | ||||
|         self::ensureKernelShutdown(); | ||||
|         $client = $this->getClientAuthenticated(); | ||||
|         $client->request(Request::METHOD_GET, sprintf('/api/1.0/relations/relationship/by-person/%d.json', $personId)); | ||||
|  | ||||
|         $response = $client->getResponse(); | ||||
|         $this->assertEquals(200, $response->getStatusCode(), 'Test to see that API response returns a status code 200'); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider relationProvider | ||||
|      */ | ||||
| @@ -137,6 +114,29 @@ final class RelationshipApiControllerTest extends WebTestCase | ||||
|         $this->assertEquals(200, $response->getStatusCode()); | ||||
|     } | ||||
|  | ||||
|     public static function relationProvider(): array | ||||
|     { | ||||
|         self::bootKernel(); | ||||
|         $em = self::getContainer()->get(EntityManagerInterface::class); | ||||
|         $personIdWithoutRelations = $em->createQueryBuilder() | ||||
|             ->select('p.id') | ||||
|             ->from(Person::class, 'p') | ||||
|             ->join('p.centerCurrent', 'center_current') | ||||
|             ->join('center_current.center', 'c') | ||||
|             ->where('c.name LIKE :name') | ||||
|             ->andWhere('NOT EXISTS (SELECT 1 FROM '.Relationship::class.' r WHERE r.fromPerson = p OR r.toPerson = p)') | ||||
|             ->setParameter('name', 'Center A') | ||||
|             ->getQuery() | ||||
|             ->setMaxResults(2) | ||||
|             ->getResult(); | ||||
|  | ||||
|         self::ensureKernelShutdown(); | ||||
|  | ||||
|         return [ | ||||
|             [$personIdWithoutRelations[0]['id'], $personIdWithoutRelations[1]['id'], self::getRandomRelation($em)->getId(), true], | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|     private static function getRandomRelation(EntityManagerInterface $em): Relation | ||||
|     { | ||||
|         if (null === self::$relations) { | ||||
|   | ||||
| @@ -45,6 +45,24 @@ final class SocialWorkEvaluationApiControllerTest extends WebTestCase | ||||
|         $em->flush(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider dataGenerateSocialActionWithEvaluations | ||||
|      */ | ||||
|     public function testListEvaluationBySocialAction(SocialAction $action, Evaluation $inactiveEvaluation): void | ||||
|     { | ||||
|         $client = $this->getClientAuthenticated(); | ||||
|  | ||||
|         $client->request('GET', sprintf('/api/1.0/person/social-work/evaluation/by-social-action/%d.json', $action->getId())); | ||||
|  | ||||
|         $this->assertResponseIsSuccessful(); | ||||
|  | ||||
|         $content = json_decode($client->getResponse()->getContent(), true, 512, JSON_THROW_ON_ERROR); | ||||
|  | ||||
|         $ids = array_map(static fn (array $item) => $item['id'], $content['results']); | ||||
|  | ||||
|         $this->assertNotContains($inactiveEvaluation->getId(), $ids); | ||||
|     } | ||||
|  | ||||
|     public static function dataGenerateSocialActionWithEvaluations(): iterable | ||||
|     { | ||||
|         self::bootKernel(); | ||||
| @@ -67,22 +85,4 @@ final class SocialWorkEvaluationApiControllerTest extends WebTestCase | ||||
|  | ||||
|         yield [$socialAction, self::$evaluationToReset]; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider dataGenerateSocialActionWithEvaluations | ||||
|      */ | ||||
|     public function testListEvaluationBySocialAction(SocialAction $action, Evaluation $inactiveEvaluation): void | ||||
|     { | ||||
|         $client = $this->getClientAuthenticated(); | ||||
|  | ||||
|         $client->request('GET', sprintf('/api/1.0/person/social-work/evaluation/by-social-action/%d.json', $action->getId())); | ||||
|  | ||||
|         $this->assertResponseIsSuccessful(); | ||||
|  | ||||
|         $content = json_decode($client->getResponse()->getContent(), true, 512, JSON_THROW_ON_ERROR); | ||||
|  | ||||
|         $ids = array_map(static fn (array $item) => $item['id'], $content['results']); | ||||
|  | ||||
|         $this->assertNotContains($inactiveEvaluation->getId(), $ids); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -21,30 +21,6 @@ use PHPUnit\Framework\TestCase; | ||||
|  */ | ||||
| final class PersonCreateEventTest extends TestCase | ||||
| { | ||||
|     public static function generateAltNames(): iterator | ||||
|     { | ||||
|         yield ['vinCENT', 'VINCENT']; | ||||
|  | ||||
|         yield ['jean-marie', 'JEAN-MARIE']; | ||||
|  | ||||
|         yield ['fastré', 'FASTRÉ']; | ||||
|  | ||||
|         yield ['émile', 'ÉMILE']; | ||||
|     } | ||||
|  | ||||
|     public static function generateNames(): iterator | ||||
|     { | ||||
|         yield ['émelie-marie', 'Émelie-Marie', 'lenaerts', 'LENAERTS']; | ||||
|  | ||||
|         yield ['jean-marie', 'Jean-Marie', 'lenaerts', 'LENAERTS']; | ||||
|  | ||||
|         yield ['vinCENT', 'Vincent', 'fastré', 'FASTRÉ']; | ||||
|  | ||||
|         yield ['Vincent', 'Vincent', 'van Gogh', 'VAN GOGH']; | ||||
|  | ||||
|         yield ['André marie', 'André Marie', 'Bah', 'BAH']; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider generateAltNames | ||||
|      */ | ||||
| @@ -61,6 +37,17 @@ final class PersonCreateEventTest extends TestCase | ||||
|         $this->assertEquals($altnameExpected, $personAltname->getLabel()); | ||||
|     } | ||||
|  | ||||
|     public static function generateAltNames(): iterator | ||||
|     { | ||||
|         yield ['vinCENT', 'VINCENT']; | ||||
|  | ||||
|         yield ['jean-marie', 'JEAN-MARIE']; | ||||
|  | ||||
|         yield ['fastré', 'FASTRÉ']; | ||||
|  | ||||
|         yield ['émile', 'ÉMILE']; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider generateNames | ||||
|      */ | ||||
| @@ -78,4 +65,17 @@ final class PersonCreateEventTest extends TestCase | ||||
|         $this->assertEquals($firstnameExpected, $person->getFirstName()); | ||||
|         $this->assertEquals($lastnameExpected, $person->getLastName()); | ||||
|     } | ||||
|  | ||||
|     public static function generateNames(): iterator | ||||
|     { | ||||
|         yield ['émelie-marie', 'Émelie-Marie', 'lenaerts', 'LENAERTS']; | ||||
|  | ||||
|         yield ['jean-marie', 'Jean-Marie', 'lenaerts', 'LENAERTS']; | ||||
|  | ||||
|         yield ['vinCENT', 'Vincent', 'fastré', 'FASTRÉ']; | ||||
|  | ||||
|         yield ['Vincent', 'Vincent', 'van Gogh', 'VAN GOGH']; | ||||
|  | ||||
|         yield ['André marie', 'André Marie', 'Bah', 'BAH']; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -77,31 +77,6 @@ final class PersonDocGenNormalizerTest extends KernelTestCase | ||||
|         $this->normalizer = self::getContainer()->get(NormalizerInterface::class); | ||||
|     } | ||||
|  | ||||
|     public static function dataGeneratorNormalizationNullOrNotNullHaveSameKeys(): iterable | ||||
|     { | ||||
|         yield [['docgen:expects' => Person::class, 'groups' => ['docgen:read']]]; | ||||
|  | ||||
|         yield [['docgen:expects' => Person::class, 'groups' => ['docgen:read'], 'docgen:person:with-household' => true]]; | ||||
|  | ||||
|         yield [['docgen:expects' => Person::class, 'groups' => ['docgen:read'], 'docgen:person:with-relations' => true]]; | ||||
|  | ||||
|         yield [['docgen:expects' => Person::class, 'groups' => ['docgen:read'], 'docgen:person:with-budget' => true]]; | ||||
|     } | ||||
|  | ||||
|     public static function generateData() | ||||
|     { | ||||
|         $person = new Person(); | ||||
|         $person | ||||
|             ->setFirstName('Renaud') | ||||
|             ->setLastName('Mégane'); | ||||
|  | ||||
|         $expected = [...self::BLANK, 'firstName' => 'Renaud', 'lastName' => 'Mégane', 'text' => 'Renaud Mégane']; | ||||
|  | ||||
|         yield [$person, $expected, 'partial normalization for a person']; | ||||
|  | ||||
|         yield [null, self::BLANK, 'normalization for a null person']; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider dataGeneratorNormalizationNullOrNotNullHaveSameKeys | ||||
|      */ | ||||
| @@ -118,6 +93,17 @@ final class PersonDocGenNormalizerTest extends KernelTestCase | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     public static function dataGeneratorNormalizationNullOrNotNullHaveSameKeys(): iterable | ||||
|     { | ||||
|         yield [['docgen:expects' => Person::class, 'groups' => ['docgen:read']]]; | ||||
|  | ||||
|         yield [['docgen:expects' => Person::class, 'groups' => ['docgen:read'], 'docgen:person:with-household' => true]]; | ||||
|  | ||||
|         yield [['docgen:expects' => Person::class, 'groups' => ['docgen:read'], 'docgen:person:with-relations' => true]]; | ||||
|  | ||||
|         yield [['docgen:expects' => Person::class, 'groups' => ['docgen:read'], 'docgen:person:with-budget' => true]]; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider generateData | ||||
|      */ | ||||
| @@ -236,6 +222,20 @@ final class PersonDocGenNormalizerTest extends KernelTestCase | ||||
|         ]), $msg); | ||||
|     } | ||||
|  | ||||
|     public static function generateData() | ||||
|     { | ||||
|         $person = new Person(); | ||||
|         $person | ||||
|             ->setFirstName('Renaud') | ||||
|             ->setLastName('Mégane'); | ||||
|  | ||||
|         $expected = [...self::BLANK, 'firstName' => 'Renaud', 'lastName' => 'Mégane', 'text' => 'Renaud Mégane']; | ||||
|  | ||||
|         yield [$person, $expected, 'partial normalization for a person']; | ||||
|  | ||||
|         yield [null, self::BLANK, 'normalization for a null person']; | ||||
|     } | ||||
|  | ||||
|     private function buildNormalizer( | ||||
|         ?PersonRender $personRender = null, | ||||
|         ?RelationshipRepository $relationshipRepository = null, | ||||
|   | ||||
| @@ -62,6 +62,24 @@ class AccompanyingPeriodCalendarGenericDocProviderTest extends KernelTestCase | ||||
|         self::assertIsInt($nb); | ||||
|     } | ||||
|  | ||||
|     public static function provideDataForAccompanyingPeriod(): iterable | ||||
|     { | ||||
|         self::bootKernel(); | ||||
|         $entityManager = self::getContainer()->get(EntityManagerInterface::class); | ||||
|  | ||||
|         if (null === $period = $entityManager->createQuery('SELECT p FROM '.AccompanyingPeriod::class.' p ') | ||||
|             ->setMaxResults(1)->getSingleResult()) { | ||||
|             throw new \RuntimeException('There is no accompanying period'); | ||||
|         } | ||||
|  | ||||
|         yield [$period, null, null, null]; | ||||
|         yield [$period, new \DateTimeImmutable('1 year ago'), null, null]; | ||||
|         yield [$period, new \DateTimeImmutable('1 year ago'), new \DateTimeImmutable('6 month ago'), null]; | ||||
|         yield [$period, new \DateTimeImmutable('1 year ago'), new \DateTimeImmutable('6 month ago'), 'text']; | ||||
|         yield [$period, null, null, 'text']; | ||||
|         yield [$period, null, new \DateTimeImmutable('6 month ago'), null]; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider provideDataForPerson | ||||
|      */ | ||||
| @@ -120,22 +138,4 @@ class AccompanyingPeriodCalendarGenericDocProviderTest extends KernelTestCase | ||||
|         yield [$person, null, null, 'text']; | ||||
|         yield [$person, null, new \DateTimeImmutable('6 month ago'), null]; | ||||
|     } | ||||
|  | ||||
|     public static function provideDataForAccompanyingPeriod(): iterable | ||||
|     { | ||||
|         self::bootKernel(); | ||||
|         $entityManager = self::getContainer()->get(EntityManagerInterface::class); | ||||
|  | ||||
|         if (null === $period = $entityManager->createQuery('SELECT p FROM '.AccompanyingPeriod::class.' p ') | ||||
|             ->setMaxResults(1)->getSingleResult()) { | ||||
|             throw new \RuntimeException('There is no accompanying period'); | ||||
|         } | ||||
|  | ||||
|         yield [$period, null, null, null]; | ||||
|         yield [$period, new \DateTimeImmutable('1 year ago'), null, null]; | ||||
|         yield [$period, new \DateTimeImmutable('1 year ago'), new \DateTimeImmutable('6 month ago'), null]; | ||||
|         yield [$period, new \DateTimeImmutable('1 year ago'), new \DateTimeImmutable('6 month ago'), 'text']; | ||||
|         yield [$period, null, null, 'text']; | ||||
|         yield [$period, null, new \DateTimeImmutable('6 month ago'), null]; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -28,6 +28,33 @@ final class TimelineAccompanyingPeriodTest extends WebTestCase | ||||
| { | ||||
|     use PrepareClientTrait; | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider provideDataPersonWithAccompanyingPeriod | ||||
|      */ | ||||
|     public function testEntriesAreShown(mixed $personId): never | ||||
|     { | ||||
|         $this->markTestSkipped('page does not work'); | ||||
|  | ||||
|         $client = $this->getClientAuthenticated(); | ||||
|  | ||||
|         $crawler = $client->request('GET', "/en/person/{$personId}/timeline"); | ||||
|  | ||||
|         $this->assertTrue( | ||||
|             $client->getResponse()->isSuccessful(), | ||||
|             'the timeline page loads sucessfully' | ||||
|         ); | ||||
|         $this->assertGreaterThan( | ||||
|             0, | ||||
|             $crawler->filter('.timeline div')->count(), | ||||
|             'the timeline page contains multiple div inside a .timeline element' | ||||
|         ); | ||||
|         $this->assertStringContainsString( | ||||
|             'est ouvert', | ||||
|             $crawler->filter('.timeline')->text(), | ||||
|             "the text 'est ouvert' is present" | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     public static function provideDataPersonWithAccompanyingPeriod() | ||||
|     { | ||||
|         self::bootKernel(); | ||||
| @@ -55,31 +82,4 @@ final class TimelineAccompanyingPeriodTest extends WebTestCase | ||||
|  | ||||
|         yield [\array_pop($personIds)['id']]; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider provideDataPersonWithAccompanyingPeriod | ||||
|      */ | ||||
|     public function testEntriesAreShown(mixed $personId): never | ||||
|     { | ||||
|         $this->markTestSkipped('page does not work'); | ||||
|  | ||||
|         $client = $this->getClientAuthenticated(); | ||||
|  | ||||
|         $crawler = $client->request('GET', "/en/person/{$personId}/timeline"); | ||||
|  | ||||
|         $this->assertTrue( | ||||
|             $client->getResponse()->isSuccessful(), | ||||
|             'the timeline page loads sucessfully' | ||||
|         ); | ||||
|         $this->assertGreaterThan( | ||||
|             0, | ||||
|             $crawler->filter('.timeline div')->count(), | ||||
|             'the timeline page contains multiple div inside a .timeline element' | ||||
|         ); | ||||
|         $this->assertStringContainsString( | ||||
|             'est ouvert', | ||||
|             $crawler->filter('.timeline')->text(), | ||||
|             "the text 'est ouvert' is present" | ||||
|         ); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -25,6 +25,20 @@ use Symfony\Component\Validator\Test\ConstraintValidatorTestCase; | ||||
|  */ | ||||
| final class MaxHolderValidatorTest extends ConstraintValidatorTestCase | ||||
| { | ||||
|     /** | ||||
|      * @dataProvider provideInvalidHousehold | ||||
|      */ | ||||
|     public function testHouseholdInvalid(Household $household, mixed $parameters) | ||||
|     { | ||||
|         $constraint = $this->getConstraint(); | ||||
|  | ||||
|         $this->validator->validate($household, $constraint); | ||||
|  | ||||
|         $this->buildViolation('msg') | ||||
|             ->setParameters($parameters) | ||||
|             ->assertRaised(); | ||||
|     } | ||||
|  | ||||
|     public static function provideInvalidHousehold() | ||||
|     { | ||||
|         $household = new Household(); | ||||
| @@ -59,20 +73,6 @@ final class MaxHolderValidatorTest extends ConstraintValidatorTestCase | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider provideInvalidHousehold | ||||
|      */ | ||||
|     public function testHouseholdInvalid(Household $household, mixed $parameters) | ||||
|     { | ||||
|         $constraint = $this->getConstraint(); | ||||
|  | ||||
|         $this->validator->validate($household, $constraint); | ||||
|  | ||||
|         $this->buildViolation('msg') | ||||
|             ->setParameters($parameters) | ||||
|             ->assertRaised(); | ||||
|     } | ||||
|  | ||||
|     protected function createValidator() | ||||
|     { | ||||
|         return new MaxHolderValidator(); | ||||
|   | ||||
| @@ -265,6 +265,10 @@ no comment found: "Aucun commentaire" | ||||
| Select a type: "Choisissez un type" | ||||
| Select a person: "Choisissez un usager" | ||||
| Kind: "Type" | ||||
| person_resource: | ||||
|     person_non_prof: "Usager/ Tiers non-professionnel" | ||||
|     thirdparty_prof: "Tiers professionnel" | ||||
|     freetext: "Description libre" | ||||
|  | ||||
|  | ||||
| # pickAPersonType | ||||
|   | ||||
| @@ -54,6 +54,25 @@ final class ReportVoterTest extends KernelTestCase | ||||
|         $this->prophet = new \Prophecy\Prophet(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider dataProvider | ||||
|      * | ||||
|      * @param type $expectedResult | ||||
|      * @param type $action | ||||
|      * @param type $message | ||||
|      */ | ||||
|     public function testAccess( | ||||
|         $expectedResult, | ||||
|         Report $report, | ||||
|         $action, | ||||
|         $message, | ||||
|         ?User $user = null, | ||||
|     ) { | ||||
|         $token = $this->prepareToken($user); | ||||
|         $result = $this->voter->vote($token, $report, [$action]); | ||||
|         $this->assertEquals($expectedResult, $result, $message); | ||||
|     } | ||||
|  | ||||
|     public function dataProvider() | ||||
|     { | ||||
|         $centerA = $this->prepareCenter(1, 'center A'); | ||||
| @@ -120,25 +139,6 @@ final class ReportVoterTest extends KernelTestCase | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider dataProvider | ||||
|      * | ||||
|      * @param type $expectedResult | ||||
|      * @param type $action | ||||
|      * @param type $message | ||||
|      */ | ||||
|     public function testAccess( | ||||
|         $expectedResult, | ||||
|         Report $report, | ||||
|         $action, | ||||
|         $message, | ||||
|         ?User $user = null, | ||||
|     ) { | ||||
|         $token = $this->prepareToken($user); | ||||
|         $result = $this->voter->vote($token, $report, [$action]); | ||||
|         $this->assertEquals($expectedResult, $result, $message); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * prepare a person. | ||||
|      * | ||||
|   | ||||
		Reference in New Issue
	
	Block a user