. */ namespace SP\Tests\Infrastructure\Auth\Repositories; use Aura\SqlQuery\Common\DeleteInterface; use Aura\SqlQuery\Common\InsertInterface; use Aura\SqlQuery\Common\SelectInterface; use Aura\SqlQuery\Common\UpdateInterface; use Aura\SqlQuery\QueryFactory; use PHPUnit\Framework\Attributes\Group; use PHPUnit\Framework\Constraint\Callback; use PHPUnit\Framework\MockObject\MockObject; use SP\Domain\Auth\Models\AuthToken as AuthTokenModel; use SP\Domain\Common\Models\Simple; use SP\Domain\Core\Dtos\ItemSearchDto; use SP\Domain\Core\Exceptions\ConstraintException; use SP\Domain\Core\Exceptions\QueryException; use SP\Domain\Database\Ports\DatabaseInterface; use SP\Infrastructure\Auth\Repositories\AuthToken; use SP\Infrastructure\Common\Repositories\DuplicatedItemException; use SP\Infrastructure\Database\QueryData; use SP\Infrastructure\Database\QueryResult; use SP\Tests\Generators\AuthTokenGenerator; use SP\Tests\UnitaryTestCase; /** * Class AuthTokenRepositoryTest * */ #[Group('unitary')] class AuthTokenTest extends UnitaryTestCase { private AuthToken $authToken; private MockObject|DatabaseInterface $database; /** * @throws ConstraintException * @throws QueryException */ public function testSearch() { $item = new ItemSearchDto(self::$faker->name); $callback = new Callback( static function (QueryData $arg) use ($item) { $query = $arg->getQuery(); $params = $query->getBindValues(); $searchStringLike = '%' . $item->getSeachString() . '%'; return count($params) === 2 && $params['userLogin'] === $searchStringLike && $params['userName'] === $searchStringLike && $arg->getMapClassName() === AuthTokenModel::class && is_a($query, SelectInterface::class) && !empty($query->getStatement()); } ); $this->database ->expects(self::once()) ->method('runQuery') ->with($callback, true); $this->authToken->search($item); } /** * @throws ConstraintException * @throws QueryException */ public function testSearchWithoutString(): void { $callback = new Callback( static function (QueryData $arg) { $query = $arg->getQuery(); return count($query->getBindValues()) === 0 && $arg->getMapClassName() === AuthTokenModel::class && is_a($query, SelectInterface::class) && !empty($query->getStatement()); } ); $this->database ->expects(self::once()) ->method('runQuery') ->with($callback, true); $this->authToken->search(new ItemSearchDto()); } /** * @throws ConstraintException * @throws QueryException */ public function testDeleteByIdBatch() { $ids = [self::$faker->randomNumber(), self::$faker->randomNumber(), self::$faker->randomNumber()]; $callback = new Callback( static function (QueryData $arg) use ($ids) { $query = $arg->getQuery(); $values = $query->getBindValues(); return count($values) === 3 && array_shift($values) === array_shift($ids) && array_shift($values) === array_shift($ids) && array_shift($values) === array_shift($ids) && $arg->getMapClassName() === Simple::class && is_a($query, DeleteInterface::class) && !empty($query->getStatement()); } ); $this->database ->expects(self::once()) ->method('runQuery') ->with($callback); $this->authToken->deleteByIdBatch($ids); } /** * @throws ConstraintException * @throws QueryException */ public function testDeleteByIdBatchWithNoIds(): void { $this->database ->expects(self::never()) ->method('runQuery'); $this->authToken->deleteByIdBatch([]); } public function testGetTokenByUserId() { $id = self::$faker->randomNumber(); $callback = new Callback( static function (QueryData $arg) use ($id) { $query = $arg->getQuery(); $params = $query->getBindValues(); return count($params) === 1 && $params['userId'] === $id && $arg->getMapClassName() === AuthTokenModel::class && is_a($query, SelectInterface::class) && !empty($query->getStatement()); } ); $this->database ->expects(self::once()) ->method('runQuery') ->with($callback); $this->authToken->getTokenByUserId($id); } public function testGetById() { $id = self::$faker->randomNumber(); $callback = new Callback( static function (QueryData $arg) use ($id) { $query = $arg->getQuery(); $params = $query->getBindValues(); return count($params) === 1 && $params['id'] === $id && $arg->getMapClassName() === AuthTokenModel::class && is_a($query, SelectInterface::class) && !empty($query->getStatement()); } ); $this->database ->expects(self::once()) ->method('runQuery') ->with($callback); $this->authToken->getById($id); } /** * @throws ConstraintException * @throws DuplicatedItemException * @throws QueryException */ public function testUpdate() { $authToken = AuthTokenGenerator::factory()->buildAuthToken(); $callbackDuplicate = new Callback( static function (QueryData $arg) use ($authToken) { $query = $arg->getQuery(); $params = $query->getBindValues(); return count($params) === 4 && $params['id'] === $authToken->getId() && $params['userId'] === $authToken->getUserId() && $params['token'] === $authToken->getToken() && $params['actionId'] === $authToken->getActionId() && is_a($query, SelectInterface::class) && !empty($query->getStatement()); } ); $callbackUpdate = new Callback( static function (QueryData $arg) use ($authToken) { $query = $arg->getQuery(); $params = $query->getBindValues(); return count($params) === 7 && $params['id'] === $authToken->getId() && $params['userId'] === $authToken->getUserId() && $params['token'] === $authToken->getToken() && $params['createdBy'] === $authToken->getCreatedBy() && $params['actionId'] === $authToken->getActionId() && $params['hash'] === $authToken->getHash() && $params['vault'] === $authToken->getVault() && is_a($query, UpdateInterface::class) && !empty($query->getStatement()); } ); $this->database ->expects(self::exactly(2)) ->method('runQuery') ->with(...self::withConsecutive([$callbackDuplicate], [$callbackUpdate])) ->willReturn(new QueryResult([]), new QueryResult([1])); $this->authToken->update($authToken); } /** * @throws ConstraintException * @throws DuplicatedItemException * @throws QueryException */ public function testUpdateWithDuplicate() { $authToken = AuthTokenGenerator::factory()->buildAuthToken(); $callback = new Callback( static function (QueryData $arg) use ($authToken) { $query = $arg->getQuery(); $params = $query->getBindValues(); return count($params) === 4 && $params['id'] === $authToken->getId() && $params['userId'] === $authToken->getUserId() && $params['token'] === $authToken->getToken() && $params['actionId'] === $authToken->getActionId() && is_a($query, SelectInterface::class) && !empty($query->getStatement()); } ); $this->database ->expects(self::once()) ->method('runQuery') ->with($callback) ->willReturn(new QueryResult([1])); $this->expectException(DuplicatedItemException::class); $this->expectExceptionMessage('Authorization already exist'); $this->authToken->update($authToken); } /** * @throws ConstraintException * @throws QueryException */ public function testRefreshVaultByUserId() { $userId = self::$faker->randomNumber(); $vault = self::$faker->sha1(); $hash = self::$faker->sha1(); $callback = new Callback( static function (QueryData $arg) use ($userId, $vault, $hash) { $query = $arg->getQuery(); $params = $query->getBindValues(); return count($params) === 3 && $params['userId'] === $userId && $params['vault'] === $vault && $params['hash'] === $hash && $arg->getOnErrorMessage() === 'Internal error' && is_a($query, UpdateInterface::class) && !empty($query->getStatement()); } ); $this->database ->expects(self::once()) ->method('runQuery') ->with($callback) ->willReturn(new QueryResult(null, 10)); $out = $this->authToken->refreshVaultByUserId($userId, $vault, $hash); self::assertEquals(10, $out); } /** * @throws ConstraintException * @throws QueryException */ public function testDelete() { $id = self::$faker->randomNumber(); $callback = new Callback( static function (QueryData $arg) use ($id) { $query = $arg->getQuery(); return $query->getBindValues()['id'] === $id && is_a($query, DeleteInterface::class) && !empty($query->getStatement()); } ); $this->database->expects(self::once())->method('runQuery')->with($callback); $this->authToken->delete($id); } public function testGetAll() { $callback = new Callback( static function (QueryData $arg) { $query = $arg->getQuery(); return $arg->getMapClassName() === AuthTokenModel::class && is_a($query, SelectInterface::class) && !empty($query->getStatement()); } ); $this->database ->expects(self::once()) ->method('runQuery') ->with($callback); $this->authToken->getAll(); } /** * @throws ConstraintException * @throws QueryException */ public function testRefreshTokenByUserId() { $userId = self::$faker->randomNumber(); $token = self::$faker->sha1(); $callback = new Callback( static function (QueryData $arg) use ($userId, $token) { $query = $arg->getQuery(); $params = $query->getBindValues(); return count($params) === 2 && $params['userId'] === $userId && $params['token'] === $token && $arg->getOnErrorMessage() === 'Internal error' && is_a($query, UpdateInterface::class) && !empty($query->getStatement()); } ); $this->database ->expects(self::once()) ->method('runQuery') ->with($callback) ->willReturn(new QueryResult([1])); $this->authToken->refreshTokenByUserId($userId, $token); } public function testGetTokenByToken() { $actionId = self::$faker->randomNumber(); $token = self::$faker->sha1(); $callback = new Callback( static function (QueryData $arg) use ($actionId, $token) { $query = $arg->getQuery(); $params = $query->getBindValues(); return count($params) === 2 && $params['actionId'] === $actionId && $params['token'] === $token && $arg->getMapClassName() === AuthTokenModel::class && is_a($query, SelectInterface::class) && !empty($query->getStatement()); } ); $this->database ->expects(self::once()) ->method('runQuery') ->with($callback); $this->authToken->getTokenByToken($actionId, $token); } /** * @throws ConstraintException * @throws DuplicatedItemException * @throws QueryException */ public function testCreate() { $authToken = AuthTokenGenerator::factory()->buildAuthToken(); $callbackDuplicate = new Callback( static function (QueryData $arg) use ($authToken) { $query = $arg->getQuery(); $params = $query->getBindValues(); return count($params) === 3 && $params['userId'] === $authToken->getUserId() && $params['token'] === $authToken->getToken() && $params['actionId'] === $authToken->getActionId() && is_a($query, SelectInterface::class) && !empty($query->getStatement()); } ); $callbackUpdate = new Callback( static function (QueryData $arg) use ($authToken) { $query = $arg->getQuery(); $params = $query->getBindValues(); return count($params) === 6 && $params['userId'] === $authToken->getUserId() && $params['token'] === $authToken->getToken() && $params['createdBy'] === $authToken->getCreatedBy() && $params['actionId'] === $authToken->getActionId() && $params['hash'] === $authToken->getHash() && $params['vault'] === $authToken->getVault() && is_a($query, InsertInterface::class) && !empty($query->getStatement()); } ); $this->database ->expects(self::exactly(2)) ->method('runQuery') ->with(...self::withConsecutive([$callbackDuplicate], [$callbackUpdate])) ->willReturn(new QueryResult([]), new QueryResult([1])); $this->authToken->create($authToken); } /** * @throws ConstraintException * @throws DuplicatedItemException * @throws QueryException */ public function testCreateWithDuplicate() { $authToken = AuthTokenGenerator::factory()->buildAuthToken(); $callback = new Callback( static function (QueryData $arg) use ($authToken) { $query = $arg->getQuery(); $params = $query->getBindValues(); return count($params) === 3 && $params['userId'] === $authToken->getUserId() && $params['token'] === $authToken->getToken() && $params['actionId'] === $authToken->getActionId() && is_a($query, SelectInterface::class) && !empty($query->getStatement()); } ); $this->database ->expects(self::once()) ->method('runQuery') ->with($callback) ->willReturn(new QueryResult([1])); $this->expectException(DuplicatedItemException::class); $this->expectExceptionMessage('Authorization already exist'); $this->authToken->create($authToken); } protected function setUp(): void { parent::setUp(); $this->database = $this->createMock(DatabaseInterface::class); $queryFactory = new QueryFactory('mysql'); $this->authToken = new AuthToken( $this->database, $this->context, $this->application->getEventDispatcher(), $queryFactory, ); } }