From 1fb90bcd26e88c48c7de7864fc98edf264231fce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20D?= Date: Mon, 5 Aug 2024 08:21:24 +0200 Subject: [PATCH] test(IT): Test account copy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rubén D --- .../Controllers/Account/AccountSaveBase.php | 3 +- .../Account/SaveCopyController.php | 25 ++-- app/modules/web/Forms/AccountForm.php | 12 +- app/modules/web/Forms/FormBase.php | 14 +- lib/SP/Domain/Common/Services/Service.php | 2 +- lib/SP/Domain/Http/Services/Request.php | 22 ++- tests/SP/IntegrationTestCase.php | 9 +- .../Account/SaveCopyControllerTest.php | 125 ++++++++++++++++++ 8 files changed, 170 insertions(+), 42 deletions(-) create mode 100644 tests/SP/Modules/Web/Controllers/Account/SaveCopyControllerTest.php diff --git a/app/modules/web/Controllers/Account/AccountSaveBase.php b/app/modules/web/Controllers/Account/AccountSaveBase.php index 14310c4a..c26f831e 100644 --- a/app/modules/web/Controllers/Account/AccountSaveBase.php +++ b/app/modules/web/Controllers/Account/AccountSaveBase.php @@ -30,6 +30,7 @@ use SP\Domain\Account\Ports\AccountService; use SP\Domain\CustomField\Ports\CustomFieldDataService; use SP\Modules\Web\Controllers\Traits\JsonTrait; use SP\Modules\Web\Forms\AccountForm; +use SP\Modules\Web\Forms\FormInterface; use SP\Mvc\Controller\ItemTrait; use SP\Mvc\Controller\WebControllerHelper; @@ -41,7 +42,7 @@ abstract class AccountSaveBase extends AccountControllerBase use ItemTrait; use JsonTrait; - protected readonly AccountForm $accountForm; + protected readonly FormInterface $accountForm; public function __construct( Application $application, diff --git a/app/modules/web/Controllers/Account/SaveCopyController.php b/app/modules/web/Controllers/Account/SaveCopyController.php index 7009af23..2ff49a08 100644 --- a/app/modules/web/Controllers/Account/SaveCopyController.php +++ b/app/modules/web/Controllers/Account/SaveCopyController.php @@ -25,22 +25,24 @@ namespace SP\Modules\Web\Controllers\Account; use Exception; -use JsonException; -use SP\Core\Acl\Acl; use SP\Core\Events\Event; use SP\Core\Events\EventMessage; use SP\Domain\Core\Acl\AclActionsInterface; +use SP\Domain\Core\Exceptions\SPException; use SP\Domain\Core\Exceptions\ValidationException; use SP\Domain\Http\Dtos\JsonMessage; +use function SP\__u; +use function SP\processException; + /** * Class SaveCopyController */ final class SaveCopyController extends AccountSaveBase { /** - * @return bool - * @throws JsonException + * @return bool|null + * @throws SPException */ public function saveCopyAction(): ?bool { @@ -49,15 +51,16 @@ final class SaveCopyController extends AccountSaveBase $accountId = $this->accountService->create($this->accountForm->getItemData()); - $accountDetails = $this->accountService->getByIdEnriched($accountId)->getAccountVData(); + $accountDetails = $this->accountService->getByIdEnriched($accountId); $this->eventDispatcher->notify( 'create.account', new Event( - $this, EventMessage::factory() - ->addDescription(__u('Account created')) - ->addDetail(__u('Account'), $accountDetails->getName()) - ->addDetail(__u('Client'), $accountDetails->getClientName()) + $this, + EventMessage::factory() + ->addDescription(__u('Account created')) + ->addDetail(__u('Account'), $accountDetails->getName()) + ->addDetail(__u('Client'), $accountDetails->getClientName()) ) ); @@ -70,8 +73,8 @@ final class SaveCopyController extends AccountSaveBase return $this->returnJsonResponseData( [ - 'itemId' => $accountId, - 'nextAction' => Acl::getActionRoute(AclActionsInterface::ACCOUNT_EDIT), + 'itemId' => $accountId, + 'nextAction' => $this->acl->getRouteFor(AclActionsInterface::ACCOUNT_EDIT), ], JsonMessage::JSON_SUCCESS, __u('Account created') diff --git a/app/modules/web/Forms/AccountForm.php b/app/modules/web/Forms/AccountForm.php index 6afd3ce6..47cce674 100644 --- a/app/modules/web/Forms/AccountForm.php +++ b/app/modules/web/Forms/AccountForm.php @@ -58,8 +58,8 @@ final class AccountForm extends FormBase implements FormInterface /** * Validar el formulario * - * @param int $action - * @param int|null $id + * @param int $action + * @param int|null $id * * @return FormInterface */ @@ -174,10 +174,10 @@ final class AccountForm extends FormBase implements FormInterface /** * @throws ValidationException */ - private function checkPassword(AccountDto $accountDto): void + private function checkPassword(AccountDto $accountDto): AccountDto { if ($accountDto->getParentId() > 0) { - return; + return $accountDto; } if (!$accountDto->getPass()) { @@ -187,6 +187,8 @@ final class AccountForm extends FormBase implements FormInterface if ($this->request->analyzeEncrypted('password_repeat') !== $accountDto->getPass()) { throw new ValidationException(__u('Passwords do not match')); } + + return $accountDto; } private function analyzeItems(AccountDto $accountDto): AccountDto @@ -226,7 +228,7 @@ final class AccountForm extends FormBase implements FormInterface } if (!$accountDto->getClientId()) { - throw new ValidationException(__u('A client name needed')); + throw new ValidationException(__u('A client is needed')); } if (!$accountDto->getCategoryId()) { diff --git a/app/modules/web/Forms/FormBase.php b/app/modules/web/Forms/FormBase.php index 3497fcca..abbc90ed 100644 --- a/app/modules/web/Forms/FormBase.php +++ b/app/modules/web/Forms/FormBase.php @@ -26,7 +26,7 @@ namespace SP\Modules\Web\Forms; use SP\Core\Application; use SP\Domain\Config\Ports\ConfigDataInterface; -use SP\Domain\Config\Services\ConfigFile; +use SP\Domain\Config\Ports\ConfigFileService; use SP\Domain\Core\Context\Context; use SP\Domain\Http\Ports\RequestService; @@ -37,21 +37,21 @@ use SP\Domain\Http\Ports\RequestService; */ abstract class FormBase { - protected ConfigFile $config; + protected ConfigFileService $config; protected ConfigDataInterface $configData; - protected Context $context; + protected Context $context; /** * FormBase constructor. * * @param Application $application * @param RequestService $request - * @param int|null $itemId + * @param int|null $itemId */ public function __construct( - Application $application, - protected RequestService $request, - protected ?int $itemId = null + Application $application, + protected readonly RequestService $request, + protected ?int $itemId = null ) { $this->config = $application->getConfig(); $this->configData = $this->config->getConfigData(); diff --git a/lib/SP/Domain/Common/Services/Service.php b/lib/SP/Domain/Common/Services/Service.php index 62a42f4b..2d12fc3a 100644 --- a/lib/SP/Domain/Common/Services/Service.php +++ b/lib/SP/Domain/Common/Services/Service.php @@ -64,7 +64,7 @@ abstract class Service final protected function getMasterKeyFromContext(): string { try { - if ($this->context instanceof SessionContext) { + if (is_a($this->context, \SP\Domain\Core\Context\SessionContext::class)) { $key = CryptSession::getSessionKey($this->context); } else { $key = $this->context->getTrasientKey(Context::MASTER_PASSWORD_KEY); diff --git a/lib/SP/Domain/Http/Services/Request.php b/lib/SP/Domain/Http/Services/Request.php index d3fe2e25..37665b25 100644 --- a/lib/SP/Domain/Http/Services/Request.php +++ b/lib/SP/Domain/Http/Services/Request.php @@ -177,10 +177,8 @@ class Request implements RequestService return $this->headers->get(Header::CACHE_CONTROL->value) === 'max-age=0'; } - public function analyzeEmail( - string $param, - ?string $default = null - ): ?string { + public function analyzeEmail(string $param, ?string $default = null): ?string + { if (!$this->params->exists($param)) { return $default; } @@ -218,10 +216,8 @@ class Request implements RequestService } } - public function analyzeString( - string $param, - ?string $default = null - ): ?string { + public function analyzeString(string $param, ?string $default = null): ?string + { if (!$this->params->exists($param)) { return $default; } @@ -229,10 +225,8 @@ class Request implements RequestService return Filter::getString($this->params->get($param)); } - public function analyzeUnsafeString( - string $param, - ?string $default = null - ): ?string { + public function analyzeUnsafeString(string $param, ?string $default = null): ?string + { if (!$this->params->exists($param)) { return $default; } @@ -248,9 +242,9 @@ class Request implements RequestService * @return array|null */ public function analyzeArray( - string $param, + string $param, ?callable $mapper = null, - mixed $default = null + mixed $default = null ): ?array { $requestValue = $this->params->get($param); diff --git a/tests/SP/IntegrationTestCase.php b/tests/SP/IntegrationTestCase.php index 019b47ec..82c24cc0 100644 --- a/tests/SP/IntegrationTestCase.php +++ b/tests/SP/IntegrationTestCase.php @@ -104,6 +104,9 @@ abstract class IntegrationTestCase extends TestCase $database = self::createStub(DatabaseInterface::class); $database->method('runQuery')->willReturnCallback($this->getDatabaseReturn()); + $database->method('beginTransaction')->willReturn(true); + $database->method('endTransaction')->willReturn(true); + $database->method('rollbackTransaction')->willReturn(true); $acl = self::createMock(AclInterface::class); $acl->method('checkUserAccess')->willReturn(true); @@ -211,7 +214,7 @@ abstract class IntegrationTestCase extends TestCase return UserProfileDataGenerator::factory()->buildProfileData(); } - protected function buildRequest(string $method, string $uri, array $params): Request + protected function buildRequest(string $method, string $uri, array $paramsGet = [], array $paramsPost = []): Request { $server = array_merge( $_SERVER, @@ -224,8 +227,8 @@ abstract class IntegrationTestCase extends TestCase ); return new Request( - array_merge($_GET, $params), - array_merge($_POST, $params), + array_merge($_GET, $paramsGet), + array_merge($_POST, $paramsPost), $_COOKIE, $server, $_FILES, diff --git a/tests/SP/Modules/Web/Controllers/Account/SaveCopyControllerTest.php b/tests/SP/Modules/Web/Controllers/Account/SaveCopyControllerTest.php new file mode 100644 index 00000000..306651ff --- /dev/null +++ b/tests/SP/Modules/Web/Controllers/Account/SaveCopyControllerTest.php @@ -0,0 +1,125 @@ +. + */ + +declare(strict_types=1); + +namespace SP\Tests\Modules\Web\Controllers\Account; + +use PHPUnit\Framework\Attributes\Group; +use PHPUnit\Framework\MockObject\Exception; +use PHPUnit\Framework\MockObject\Stub; +use Psr\Container\ContainerExceptionInterface; +use Psr\Container\NotFoundExceptionInterface; +use SP\Domain\Core\Context\SessionContext; +use SP\Domain\Core\Crypt\CryptInterface; +use SP\Domain\Core\Crypt\VaultInterface; +use SP\Domain\Core\Exceptions\InvalidClassException; +use SP\Infrastructure\Database\QueryData; +use SP\Infrastructure\Database\QueryResult; +use SP\Infrastructure\File\FileException; +use SP\Tests\Generators\AccountDataGenerator; +use SP\Tests\IntegrationTestCase; + +/** + * Class SaveCopyControllerTest + */ +#[Group('integration')] +class SaveCopyControllerTest extends IntegrationTestCase +{ + + /** + * @throws ContainerExceptionInterface + * @throws Exception + * @throws NotFoundExceptionInterface + * @throws InvalidClassException + * @throws FileException + */ + public function testSaveCopyAction() + { + $crypt = $this->createStub(CryptInterface::class); + $crypt->method('decrypt')->willReturn('some_data'); + $crypt->method('encrypt')->willReturn('some_data'); + + $definitions = $this->getModuleDefinitions(); + $definitions[CryptInterface::class] = $crypt; + + $account = AccountDataGenerator::factory()->buildAccount(); + + $paramsPost = [ + 'name' => $account->getName(), + 'login' => $account->getLogin(), + 'client_id' => $account->getClientId(), + 'category_id' => $account->getCategoryId(), + 'password' => $account->getPass(), + 'password_repeat' => $account->getPass(), + 'owner_id' => $account->getUserId(), + 'notes' => $account->getNotes(), + 'private_enabled' => $account->getIsPrivate(), + 'private_group_enabled' => $account->getIsPrivateGroup(), + 'password_date_expire_unix' => $account->getPassDate(), + 'parent_account_id' => $account->getParentId(), + 'main_usergroup_id' => $account->getUserGroupId(), + 'other_users_view_update' => 1, + 'other_users_view' => [1, 2, 3], + 'other_users_edit_update' => 1, + 'other_users_edit' => [4, 5, 6], + 'other_usergroups_view_update' => 1, + 'other_usergroups_view' => [8, 9, 10], + 'other_usergroups_edit_update' => 1, + 'other_usergroups_edit' => [11, 12, 13], + 'tags_update' => 1, + 'tags' => [15, 16, 17], + ]; + + $container = $this->buildContainer( + $definitions, + $this->buildRequest('post', 'index.php', ['r' => 'account/saveCopy'], $paramsPost) + ); + + $this->runApp($container); + + $this->expectOutputString( + '{"status":0,"description":"Account created","data":{"itemId":100,"nextAction":""},"messages":[]}' + ); + } + + protected function getDatabaseReturn(): callable + { + return function (QueryData $queryData): QueryResult { + return new QueryResult([], 0, 100); + }; + } + + protected function getContext(): SessionContext|Stub + { + $vault = self::createStub(VaultInterface::class); + $vault->method('getData') + ->willReturn('some_data'); + + $context = parent::getContext(); + $context->method('getVault')->willReturn($vault); + + return $context; + } +}