diff --git a/tests/Data/diagrams/no_title.mmd b/tests/Data/diagrams/no_title.mmd new file mode 100644 index 00000000..3fbcd096 --- /dev/null +++ b/tests/Data/diagrams/no_title.mmd @@ -0,0 +1,3 @@ +classDiagram + class NoTitle { + } diff --git a/tests/Data/diagrams/user.mmd b/tests/Data/diagrams/user.mmd new file mode 100644 index 00000000..0517ca10 --- /dev/null +++ b/tests/Data/diagrams/user.mmd @@ -0,0 +1,10 @@ +--- +title: User +--- +classDiagram + class UserInterface { + <> + +getRoles() array + +getUserIdentifier() string + +eraseCredentials() + } diff --git a/tests/Security/EntityVoterTest.php b/tests/Security/EntityVoterTest.php index b9579e71..574d81ec 100644 --- a/tests/Security/EntityVoterTest.php +++ b/tests/Security/EntityVoterTest.php @@ -14,6 +14,8 @@ use App\Entity\Calculation; use App\Entity\User; +use App\Enums\EntityName; +use App\Enums\EntityPermission; use App\Interfaces\RoleInterface; use App\Security\EntityVoter; use App\Service\ApplicationService; @@ -35,7 +37,14 @@ class EntityVoterTest extends TestCase */ protected function setUp(): void { - $this->voter = new EntityVoter($this->createMock(ApplicationService::class)); + $builder = new RoleBuilderService(); + $service = $this->createMock(ApplicationService::class); + $service->method('getAdminRights') + ->willReturn($builder->getRoleAdmin()->getRights()); + $service->method('getUserRights') + ->willReturn($builder->getRoleUser()->getRights()); + + $this->voter = new EntityVoter($service); } public static function getSupportsAttribute(): \Iterator @@ -65,6 +74,19 @@ public function testAbstainSubject(): void } public function testAdmin(): void + { + $builder = new RoleBuilderService(); + $role = $builder->getRoleAdmin(); + $user = $this->getAdminUser() + ->setRights($role->getRights()); + + $attribute = 'ADD'; + $subject = User::class; + $expected = VoterInterface::ACCESS_GRANTED; + $this->assertVote($user, $subject, $attribute, $expected); + } + + public function testAdminOverwrite(): void { $builder = new RoleBuilderService(); $role = $builder->getRoleAdmin(); @@ -87,6 +109,20 @@ public function testDisable(): void $this->assertVote($user, $subject, $attribute, $expected); } + public function testEntityName(): void + { + $user = $this->getAdminUser(); + $expected = VoterInterface::ACCESS_ABSTAIN; + $this->assertVote($user, EntityName::CALCULATION, 'fake', $expected); + } + + public function testEntityPermission(): void + { + $user = $this->getAdminUser(); + $expected = VoterInterface::ACCESS_ABSTAIN; + $this->assertVote($user, 'fake', EntityPermission::ADD, $expected); + } + public function testSuperAdmin(): void { $user = $this->getSuperAdminUser(); @@ -103,6 +139,55 @@ public function testSupportsAttribute(string $value, bool $expected): void self::assertSame($expected, $actual); } + public function testUser(): void + { + $builder = new RoleBuilderService(); + $role = $builder->getRoleUser(); + $user = $this->getDefaultUser() + ->setRights($role->getRights()); + + $attribute = 'ADD'; + $subject = Calculation::class; + $expected = VoterInterface::ACCESS_GRANTED; + $this->assertVote($user, $subject, $attribute, $expected); + } + + /** + * @throws \ReflectionException + * + * @psalm-suppress UnusedMethodCall + */ + public function testVoteOnAttribute(): void + { + $class = new \ReflectionClass($this->voter); + $method = $class->getMethod('voteOnAttribute'); + $method->setAccessible(true); + + $builder = new RoleBuilderService(); + $role = $builder->getRoleUser(); + $user = $this->getDefaultUser() + ->setRights($role->getRights()); + $token = $this->getUserToken($user); + + $args = [ + 'fake', + EntityName::CALCULATION->name, + $token, + ]; + /** @psalm-var bool $actual */ + $actual = $method->invoke($this->voter, ...$args); + self::assertFalse($actual); + + $args = [ + EntityPermission::ADD->name, + 'fake', + $token, + ]; + /** @psalm-var bool $actual */ + $actual = $method->invoke($this->voter, ...$args); + self::assertFalse($actual); + } + private function assertVote(User $user, mixed $subject, mixed $attribute, mixed $expected): void { $token = $this->getUserToken($user); diff --git a/tests/Service/CalculationUpdateServiceTest.php b/tests/Service/CalculationUpdateServiceTest.php index 93988c2a..12ed2731 100644 --- a/tests/Service/CalculationUpdateServiceTest.php +++ b/tests/Service/CalculationUpdateServiceTest.php @@ -12,11 +12,10 @@ namespace App\Tests\Service; -use App\Entity\Calculation; -use App\Entity\CalculationState; use App\Service\CalculationUpdateService; use App\Tests\DatabaseTrait; use App\Tests\DateAssertTrait; +use App\Tests\EntityTrait\CalculationTrait; use App\Tests\Web\AbstractAuthenticateWebTestCase; use App\Utils\DateUtils; use App\Utils\FormatUtils; @@ -30,9 +29,19 @@ #[CoversClass(CalculationUpdateService::class)] class CalculationUpdateServiceTest extends AbstractAuthenticateWebTestCase { + use CalculationTrait; use DatabaseTrait; use DateAssertTrait; + /** + * @throws ORMException + */ + protected function tearDown(): void + { + $this->deleteCalculation(); + parent::tearDown(); + } + /** * @throws \Exception */ @@ -104,20 +113,35 @@ public function testUpdateEmpty(): void /** * @throws ORMException */ - public function testUpdateOne(): void + public function testUpdateNoCalculation(): void { + $date = $this->getDateTo(); + $state = $this->getCalculationState(); + $calculation = $this->getCalculation($state); + $calculation->setDate($date) + ->setOverallTotal(0.0); + $this->addEntity($calculation); + $this->loginUsername(self::ROLE_ADMIN); - $state = new CalculationState(); - $state->setCode('code'); - $this->addEntity($state); + $service = $this->getService(CalculationUpdateService::class); + $query = $service->createQuery(); + + $result = $service->update($query); + self::assertCount(0, $result); + self::assertCount(0, $result->getResults()); + self::assertFalse($result->isValid()); + } + /** + * @throws ORMException + */ + public function testUpdateOne(): void + { $date = $this->getDateTo(); - $calculation = new Calculation(); - $calculation->setState($state) - ->setCustomer('customer') - ->setDescription('description') - ->setOverallTotal(100.0) - ->setDate($date); + $state = $this->getCalculationState(); + $calculation = $this->getCalculation($state); + $calculation->setDate($date) + ->setOverallTotal(100.0); $this->addEntity($calculation); $this->loginUsername(self::ROLE_ADMIN); @@ -128,9 +152,29 @@ public function testUpdateOne(): void self::assertCount(1, $result); self::assertCount(1, $result->getResults()); self::assertTrue($result->isValid()); + } - $this->deleteEntity($calculation); - $this->deleteEntity($state); + /** + * @throws ORMException + */ + public function testUpdateOneNoSimulate(): void + { + $date = $this->getDateTo(); + $state = $this->getCalculationState(); + $calculation = $this->getCalculation($state); + $calculation->setDate($date) + ->setOverallTotal(100.0); + $this->addEntity($calculation); + + $this->loginUsername(self::ROLE_ADMIN); + $service = $this->getService(CalculationUpdateService::class); + $query = $service->createQuery(); + $query->setSimulate(false); + + $result = $service->update($query); + self::assertCount(1, $result); + self::assertCount(1, $result->getResults()); + self::assertTrue($result->isValid()); } /** diff --git a/tests/Service/DiagramServiceTest.php b/tests/Service/DiagramServiceTest.php new file mode 100644 index 00000000..7775648b --- /dev/null +++ b/tests/Service/DiagramServiceTest.php @@ -0,0 +1,78 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace App\Tests\Service; + +use App\Service\DiagramService; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\TestCase; +use Psr\Cache\InvalidArgumentException; +use Symfony\Component\Cache\Adapter\ArrayAdapter; + +#[CoversClass(DiagramService::class)] +class DiagramServiceTest extends TestCase +{ + private DiagramService $service; + + protected function setUp(): void + { + $path = __DIR__ . '/../Data/diagrams'; + $cache = new ArrayAdapter(); + $this->service = new DiagramService($path, $cache); + } + + /** + * @throws InvalidArgumentException + */ + public function testCount(): void + { + $files = $this->service->getFiles(); + self::assertCount(2, $files); + } + + /** + * @throws InvalidArgumentException + */ + public function testGetFileFound(): void + { + $expected = 'user'; + $actual = $this->service->getFile($expected); + self::assertIsArray($actual); + self::assertArrayHasKey('name', $actual); + self::assertArrayHasKey('title', $actual); + self::assertArrayHasKey('content', $actual); + self::assertSame($expected, $actual['name']); + } + + /** + * @throws InvalidArgumentException + */ + public function testGetFileNotFound(): void + { + $actual = $this->service->getFile('fake_name'); + self::assertNull($actual); + } + + /** + * @throws InvalidArgumentException + */ + public function testGetFileNoTitle(): void + { + $expected = 'no_title'; + $actual = $this->service->getFile($expected); + self::assertIsArray($actual); + self::assertArrayHasKey('name', $actual); + self::assertArrayHasKey('title', $actual); + self::assertArrayHasKey('content', $actual); + self::assertSame($expected, $actual['name']); + } +} diff --git a/tests/Service/RecaptchaResponseServiceTest.php b/tests/Service/RecaptchaResponseServiceTest.php new file mode 100644 index 00000000..7c1de86e --- /dev/null +++ b/tests/Service/RecaptchaResponseServiceTest.php @@ -0,0 +1,49 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace App\Tests\Service; + +use App\Service\RecaptchaResponseService; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\TestCase; +use ReCaptcha\Response; + +#[CoversClass(RecaptchaResponseService::class)] +class RecaptchaResponseServiceTest extends TestCase +{ + public function testFormatSuccess(): void + { + $response = new Response(true); + $service = new RecaptchaResponseService(); + $actual = $service->format($response); + self::assertStringContainsString('success', $actual); + self::assertStringContainsString('true', $actual); + } + + public function testFormatWithChallenge(): void + { + $response = new Response(true, challengeTs: '2024-10-02'); + $service = new RecaptchaResponseService(); + $actual = $service->format($response); + self::assertStringContainsString('success', $actual); + self::assertStringContainsString('challengeTs', $actual); + } + + public function testFormatWithErrorCodes(): void + { + $response = new Response(true, ['Fake Error']); + $service = new RecaptchaResponseService(); + $actual = $service->format($response); + self::assertStringContainsString('error-codes', $actual); + self::assertStringContainsString('Fake Error', $actual); + } +} diff --git a/tests/Service/RoleBuilderServiceTest.php b/tests/Service/RoleBuilderServiceTest.php index 8910e918..d1a38b5b 100644 --- a/tests/Service/RoleBuilderServiceTest.php +++ b/tests/Service/RoleBuilderServiceTest.php @@ -12,8 +12,10 @@ namespace App\Tests\Service; +use App\Entity\User; use App\Enums\EntityPermission; use App\Interfaces\RoleInterface; +use App\Model\Role; use App\Service\RoleBuilderService; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\TestCase; @@ -28,11 +30,67 @@ protected function setUp(): void $this->service = new RoleBuilderService(); } + public function testGetRoleAdmin(): void + { + $user = new User(); + $user->setRole(RoleInterface::ROLE_ADMIN); + $role = $this->service->getRole($user); + self::assertRoleAdmin($role); + } + + public function testGetRoleDisabled(): void + { + $user = new User(); + $user->setEnabled(false); + $role = $this->service->getRole($user); + self::assertRoleDisabled($role); + } + + public function testGetRoleSuperAdmin(): void + { + $user = new User(); + $user->setRole(RoleInterface::ROLE_SUPER_ADMIN); + $role = $this->service->getRole($user); + self::assertRoleSuperAdmin($role); + } + + public function testGetRoleUser(): void + { + $user = new User(); + $user->setRole(RoleInterface::ROLE_USER); + $role = $this->service->getRole($user); + self::assertRoleUser($role); + } + public function testRoleAdmin(): void + { + $role = $this->service->getRoleAdmin(); + self::assertRoleAdmin($role); + } + + public function testRoleDisabled(): void + { + $role = $this->service->getRoleDisabled(); + self::assertRoleDisabled($role); + } + + public function testRoleSuperAdmin(): void + { + $role = $this->service->getRoleSuperAdmin(); + self::assertRoleSuperAdmin($role); + } + + public function testRoleUser(): void + { + $role = $this->service->getRoleUser(); + self::assertRoleUser($role); + } + + protected static function assertRoleAdmin(Role $role): void { $permission = EntityPermission::getAllPermission(); - $role = $this->service->getRoleAdmin(); + self::assertFalse($role->isOverwrite()); self::assertSame(RoleInterface::ROLE_ADMIN, $role->getName()); self::assertEqualsCanonicalizing($permission, $role->CalculationRights); self::assertEqualsCanonicalizing($permission, $role->CalculationStateRights); @@ -46,11 +104,10 @@ public function testRoleAdmin(): void self::assertEqualsCanonicalizing($permission, $role->UserRights); } - public function testRoleDisabled(): void + protected static function assertRoleDisabled(Role $role): void { $permission = EntityPermission::getNonePermission(); - $role = $this->service->getRoleDisabled(); self::assertTrue($role->isOverwrite()); self::assertSame(RoleInterface::ROLE_USER, $role->getName()); self::assertEqualsCanonicalizing($permission, $role->CalculationRights); @@ -65,11 +122,10 @@ public function testRoleDisabled(): void self::assertEqualsCanonicalizing($permission, $role->CustomerRights); } - public function testRoleSuperAdmin(): void + protected static function assertRoleSuperAdmin(Role $role): void { $permission = EntityPermission::getAllPermission(); - $role = $this->service->getRoleSuperAdmin(); self::assertFalse($role->isOverwrite()); self::assertSame(RoleInterface::ROLE_SUPER_ADMIN, $role->getName()); self::assertEqualsCanonicalizing($permission, $role->CalculationRights); @@ -84,13 +140,12 @@ public function testRoleSuperAdmin(): void self::assertEqualsCanonicalizing($permission, $role->CustomerRights); } - public function testRoleUser(): void + protected static function assertRoleUser(Role $role): void { $all = EntityPermission::getAllPermission(); $none = EntityPermission::getNonePermission(); $default = EntityPermission::getDefaultPermission(); - $role = $this->service->getRoleUser(); self::assertFalse($role->isOverwrite()); self::assertSame(RoleInterface::ROLE_USER, $role->getName()); self::assertEqualsCanonicalizing($all, $role->CalculationRights); diff --git a/tests/Service/TimelineServiceTest.php b/tests/Service/TimelineServiceTest.php new file mode 100644 index 00000000..a0a82148 --- /dev/null +++ b/tests/Service/TimelineServiceTest.php @@ -0,0 +1,94 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace App\Tests\Service; + +use App\Entity\Calculation; +use App\Repository\CalculationRepository; +use App\Service\TimelineService; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\MockObject\Exception; +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; + +#[CoversClass(TimelineService::class)] +class TimelineServiceTest extends TestCase +{ + /** + * @throws Exception|\Exception + */ + public function testCurrent(): void + { + $repository = $this->createMockRepository(); + $service = new TimelineService($repository); + $actual = $service->current(); + self::assertArrayHasKey('count', $actual); + self::assertSame(0, $actual['count']); + } + + /** + * @throws Exception|\Exception + */ + public function testCurrentWithDates(): void + { + $calculation = new Calculation(); + $repository = $this->createMockRepository($calculation); + $service = new TimelineService($repository); + $actual = $service->current(); + self::assertArrayHasKey('count', $actual); + self::assertSame(1, $actual['count']); + } + + /** + * @throws Exception|\Exception + */ + public function testFirst(): void + { + $repository = $this->createMockRepository(); + $service = new TimelineService($repository); + $actual = $service->first(); + self::assertArrayHasKey('count', $actual); + self::assertSame(0, $actual['count']); + } + + /** + * @throws Exception|\Exception + */ + public function testLast(): void + { + $repository = $this->createMockRepository(); + $service = new TimelineService($repository); + $actual = $service->last(); + self::assertArrayHasKey('count', $actual); + self::assertSame(0, $actual['count']); + } + + /** + * @throws Exception + */ + private function createMockRepository(?Calculation $calculation = null): MockObject&CalculationRepository + { + $date = new \DateTime('today'); + $repository = $this->createMock(CalculationRepository::class); + + if ($calculation instanceof Calculation) { + $repository->method('getByInterval') + ->willReturn([$calculation]); + $date = $calculation->getDate(); + } + + $repository->method('getMinMaxDates') + ->willReturn([$date, $date]); + + return $repository; + } +}