From 0e93b737e4165fe9eab97a0c60f590e9900e2d86 Mon Sep 17 00:00:00 2001 From: Alejandro Celaya Date: Fri, 22 May 2026 17:46:26 +0200 Subject: [PATCH 1/2] Migrate form PHP_CodeSniffer to Mago for code linting and formatting --- .gitattributes | 2 +- CHANGELOG.md | 3 +- composer.json | 10 +- mago.toml | 73 +++++ phpcs.xml | 16 -- src/Builder/ShlinkClientBuilder.php | 3 +- src/Builder/SingletonShlinkClientBuilder.php | 33 ++- src/Config/ArrayShlinkConfig.php | 10 +- src/Config/EnvShlinkConfig.php | 10 +- src/Config/ShlinkConfig.php | 4 +- src/Domains/DomainsClient.php | 4 +- src/Domains/Model/Domain.php | 4 +- src/Domains/Model/DomainRedirects.php | 3 +- src/Domains/Model/DomainRedirectsConfig.php | 4 +- src/Exception/ExceptionInterface.php | 4 +- src/Http/ApiVersion.php | 2 + src/Http/ErrorType.php | 2 + src/Http/Exception/HttpException.php | 2 +- src/Http/HttpClient.php | 9 +- src/Model/ListEndpointIterator.php | 4 +- src/RedirectRules/Model/RedirectCondition.php | 5 +- .../Model/RedirectConditionType.php | 2 + src/RedirectRules/Model/RedirectRule.php | 6 +- src/RedirectRules/Model/RedirectRuleData.php | 4 +- src/RedirectRules/Model/RedirectRulesList.php | 6 +- src/RedirectRules/Model/SetRedirectRules.php | 4 +- src/RedirectRules/RedirectRulesClient.php | 4 +- src/ShlinkClient.php | 3 +- src/ShortUrls/Model/Device.php | 2 + src/ShortUrls/Model/ShortUrl.php | 3 +- src/ShortUrls/Model/ShortUrlIdentifier.php | 4 +- src/ShortUrls/Model/ShortUrlMeta.php | 3 +- src/ShortUrls/Model/ShortUrlPayloadTrait.php | 4 +- src/ShortUrls/Model/ShortUrlsFilter.php | 4 +- src/ShortUrls/Model/ShortUrlsList.php | 2 +- src/ShortUrls/ShortUrlsClient.php | 4 +- src/Tags/Model/TagRenaming.php | 4 +- src/Tags/Model/TagWithStats.php | 4 +- src/Tags/Model/TagsFilter.php | 8 +- src/Tags/Model/TagsMode.php | 2 + src/Tags/TagsClient.php | 4 +- src/Visits/Model/OrphanVisit.php | 4 +- src/Visits/Model/OrphanVisitType.php | 2 + src/Visits/Model/Visit.php | 3 +- src/Visits/Model/VisitInterface.php | 6 + src/Visits/Model/VisitLocation.php | 3 +- src/Visits/Model/VisitsDeletion.php | 4 +- src/Visits/Model/VisitsFilterPayloadTrait.php | 4 +- src/Visits/Model/VisitsList.php | 4 +- src/Visits/Model/VisitsOverview.php | 4 +- src/Visits/Model/VisitsSummary.php | 4 +- src/Visits/VisitsClient.php | 4 +- test-integration/Tags/TagsClientTest.php | 7 +- .../SingletonShlinkClientBuilderTest.php | 24 +- test/Config/ArrayShlinkConfigTest.php | 16 +- test/Config/EnvShlinkConfigTest.php | 16 +- test/Domains/DomainsClientTest.php | 38 ++- .../Exception/DomainNotFoundExceptionTest.php | 28 +- .../Model/DomainRedirectsConfigTest.php | 12 +- test/Http/Exception/HttpExceptionTest.php | 2 +- test/Http/HttpClientTest.php | 76 +++-- .../Model/RedirectRuleDataTest.php | 17 +- .../Model/SetRedirectRulesTest.php | 90 +++--- .../RedirectRules/RedirectRulesClientTest.php | 88 +++--- test/ShlinkClientTest.php | 260 ++++++++++++------ .../DeleteShortUrlThresholdExceptionTest.php | 34 ++- .../Exception/InvalidLongUrlExceptionTest.php | 28 +- .../Exception/NonUniqueSlugExceptionTest.php | 32 ++- .../ShortUrlNotFoundExceptionTest.php | 45 ++- test/ShortUrls/Model/ShortUrlCreationTest.php | 14 +- test/ShortUrls/Model/ShortUrlEditionTest.php | 8 +- test/ShortUrls/Model/ShortUrlMetaTest.php | 15 +- test/ShortUrls/Model/ShortUrlTest.php | 18 +- test/ShortUrls/Model/ShortUrlsFilterTest.php | 22 +- test/ShortUrls/ShortUrlsClientTest.php | 150 +++++----- .../ForbiddenTagOperationExceptionTest.php | 12 +- .../Exception/TagConflictExceptionTest.php | 32 ++- .../Exception/TagNotFoundExceptionTest.php | 28 +- test/Tags/Model/TagsFilterTest.php | 24 +- test/Tags/TagsClientTest.php | 97 ++++--- test/Visits/Model/OrphanVisitTest.php | 15 +- test/Visits/Model/VisitsFilterTest.php | 11 +- test/Visits/VisitsClientTest.php | 177 +++++++----- 83 files changed, 1056 insertions(+), 706 deletions(-) create mode 100644 mago.toml delete mode 100644 phpcs.xml diff --git a/.gitattributes b/.gitattributes index 913b096..3b10ee5 100644 --- a/.gitattributes +++ b/.gitattributes @@ -8,6 +8,6 @@ test-integration export-ignore CHANGELOG.md export-ignore docker-compose.yml export-ignore indocker export-ignore -phpcs.xml export-ignore +mago.toml export-ignore phpunit.xml.dist export-ignore phpunit-integration.xml export-ignore diff --git a/CHANGELOG.md b/CHANGELOG.md index a0bc93b..086876c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,12 +4,13 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com), and this project adheres to [Semantic Versioning](https://semver.org). -## [Unreleased] +## [3.2.0] - 2026-05-22 ### Added * *Nothing* ### Changed * Update to PHPUnit 13 +* Migrate form PHP_CodeSniffer to Mago for code linting and formatting. ### Deprecated * *Nothing* diff --git a/composer.json b/composer.json index 5ec14eb..b51ea71 100644 --- a/composer.json +++ b/composer.json @@ -16,13 +16,13 @@ "psr/http-factory": "^1.1" }, "require-dev": { + "carthage-software/mago": "^1.28", "devster/ubench": "^2.1", "guzzlehttp/guzzle": "^7.10", "phpstan/phpstan": "^2.1", "phpstan/phpstan-phpunit": "^2.0", "phpunit/phpcov": "^12.0", "phpunit/phpunit": "^13.0", - "shlinkio/php-coding-standard": "~2.5.0", "symfony/var-dumper": "^8.0" }, "autoload": { @@ -42,8 +42,12 @@ "@stan", "@test:unit" ], - "cs": "phpcs", - "cs:fix": "phpcbf", + "lint": "mago lint", + "lint:fix": "mago lint --fix", + "format": "mago format", + "format:check": "mago format --check", + "cs": ["@lint", "@format:check"], + "cs:fix": ["@lint:fix", "@format"], "stan": "phpstan analyse", "test:unit": "phpunit --order-by=random --testdox --testdox-summary", "test:unit:ci": [ diff --git a/mago.toml b/mago.toml new file mode 100644 index 0000000..dea99e0 --- /dev/null +++ b/mago.toml @@ -0,0 +1,73 @@ +#:schema https://mago.carthage.software/1.27.1/schema.json +# Welcome to Mago! +# For full documentation, see https://mago.carthage.software/tools/overview +version = "1" +php-version = "8.4.0" + +[source] +workspace = "." +paths = ["src", "test", "test-integration"] +excludes = ["vendor"] + +[source.glob] +literal-separator = true + +[formatter] +print-width = 120 +tab-width = 4 +use-tabs = false +null-type-hint = "null_pipe_last" +space-before-arrow-function-parameter-list-parenthesis = true +break-promoted-properties-list = false +parameter-attribute-on-new-line = false +preserve-breaking-member-access-chain = true +preserve-breaking-argument-list = true +preserve-breaking-array-like = true +preserve-breaking-parameter-list = true +preserve-breaking-attribute-list = true +preserve-breaking-conditional-expression = true +preserve-breaking-condition-expression = true +preserve-redundant-logical-binary-expression-parentheses = true + +[linter] +integrations = ["phpunit"] + +[linter.rules] +no-literal-password = { exclude = ["test"] } +no-empty-catch-clause = { exclude = ["test"] } +no-empty-loop = { exclude = ["test"] } +loop-does-not-iterate = { exclude = ["test"] } + +prefer-static-closure = { level = "warning" } +array-style = { level = "warning" } +prefer-early-continue = { max_allowed_statements = 2 } +no-fully-qualified-global-class-like = { enabled = true, level = "warning" } +no-fully-qualified-global-constant = { enabled = true, level = "warning" } +no-fully-qualified-global-function = { enabled = true, level = "warning" } +ambiguous-constant-access = { enabled = true, level = "warning" } +ambiguous-function-call = { enabled = true, level = "warning" } + +no-multi-assignments = { enabled = false } +no-assign-in-condition = { enabled = false } +literal-named-argument = { enabled = false } +tagged-fixme = { enabled = false } +tagged-todo = { enabled = false } +no-boolean-flag-parameter = { enabled = false } +no-else-clause = { enabled = false } +no-isset = { enabled = false } +no-empty = { enabled = false } +no-shorthand-ternary = { enabled = false } +no-ini-set = { enabled = false } +too-many-enum-cases = { enabled = false } +function-name = { enabled = false } + +# TODO Fine tune these +too-many-methods = { enabled = false } +too-many-properties = { enabled = false } +excessive-parameter-list = { enabled = false } +cyclomatic-complexity = { enabled = false } +kan-defect = { enabled = false } +halstead = { effort-threshold = 7000, enabled = false } + +# TODO Enable this +sensitive-parameter = { enabled = false } diff --git a/phpcs.xml b/phpcs.xml deleted file mode 100644 index 6518077..0000000 --- a/phpcs.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - Coding standard - - - - - - - - - - src - test - test-integration - diff --git a/src/Builder/ShlinkClientBuilder.php b/src/Builder/ShlinkClientBuilder.php index ecdcad0..2d4f906 100644 --- a/src/Builder/ShlinkClientBuilder.php +++ b/src/Builder/ShlinkClientBuilder.php @@ -29,8 +29,7 @@ public function __construct( private RequestFactoryInterface $requestFactory, private StreamFactoryInterface $streamFactory, private HttpDebuggerInterface|null $debugger = null, - ) { - } + ) {} public function buildShortUrlsClient(ShlinkConfigInterface $config): ShortUrlsClientInterface { diff --git a/src/Builder/SingletonShlinkClientBuilder.php b/src/Builder/SingletonShlinkClientBuilder.php index b176be1..94b12c8 100644 --- a/src/Builder/SingletonShlinkClientBuilder.php +++ b/src/Builder/SingletonShlinkClientBuilder.php @@ -17,49 +17,52 @@ class SingletonShlinkClientBuilder implements ShlinkClientBuilderInterface { private array $instances = []; - public function __construct(private readonly ShlinkClientBuilderInterface $wrapped) - { - } + public function __construct(private readonly ShlinkClientBuilderInterface $wrapped) {} public function buildShortUrlsClient(ShlinkConfigInterface $config): ShortUrlsClientInterface { $key = $this->configToKey($config); - return $this->instances[ShortUrlsClientInterface::class][$key] ?? ( - $this->instances[ShortUrlsClientInterface::class][$key] = $this->wrapped->buildShortUrlsClient($config) + return ( + $this->instances[ShortUrlsClientInterface::class][$key] ?? ($this->instances[ShortUrlsClientInterface::class][$key] = + $this->wrapped->buildShortUrlsClient($config)) ); } public function buildVisitsClient(ShlinkConfigInterface $config): VisitsClientInterface { $key = $this->configToKey($config); - return $this->instances[VisitsClientInterface::class][$key] ?? ( - $this->instances[VisitsClientInterface::class][$key] = $this->wrapped->buildVisitsClient($config) + return ( + $this->instances[VisitsClientInterface::class][$key] ?? ($this->instances[VisitsClientInterface::class][$key] = + $this->wrapped->buildVisitsClient($config)) ); } public function buildTagsClient(ShlinkConfigInterface $config): TagsClientInterface { $key = $this->configToKey($config); - return $this->instances[TagsClientInterface::class][$key] ?? ( - $this->instances[TagsClientInterface::class][$key] = $this->wrapped->buildTagsClient($config) + return ( + $this->instances[TagsClientInterface::class][$key] ?? ($this->instances[TagsClientInterface::class][$key] = + $this->wrapped->buildTagsClient($config)) ); } public function buildDomainsClient(ShlinkConfigInterface $config): DomainsClientInterface { $key = $this->configToKey($config); - return $this->instances[DomainsClientInterface::class][$key] ?? ( - $this->instances[DomainsClientInterface::class][$key] = $this->wrapped->buildDomainsClient($config) + return ( + $this->instances[DomainsClientInterface::class][$key] ?? ($this->instances[DomainsClientInterface::class][$key] = + $this->wrapped->buildDomainsClient($config)) ); } public function buildRedirectRulesClient(ShlinkConfigInterface $config): RedirectRulesClientInterface { $key = $this->configToKey($config); - return $this->instances[RedirectRulesClientInterface::class][$key] ?? ( - $this->instances[RedirectRulesClientInterface::class][$key] = $this->wrapped->buildRedirectRulesClient( - $config, - ) + return ( + $this->instances[RedirectRulesClientInterface::class][$key] ?? ($this->instances[RedirectRulesClientInterface::class][$key] = + $this->wrapped->buildRedirectRulesClient( + $config, + )) ); } diff --git a/src/Config/ArrayShlinkConfig.php b/src/Config/ArrayShlinkConfig.php index b6274dc..c43ef8e 100644 --- a/src/Config/ArrayShlinkConfig.php +++ b/src/Config/ArrayShlinkConfig.php @@ -15,19 +15,15 @@ public const API_KEY_PROP = 'apiKey'; public const VERSION_PROP = 'version'; - private function __construct(private ShlinkConfigInterface $wrapped) - { - } + private function __construct(private ShlinkConfigInterface $wrapped) {} /** * @throws InvalidConfigException */ public static function fromArray(array $config): self { - return new self(ShlinkConfig::fromRawConfig(new class ($config) implements RawConfigInterface { - public function __construct(private readonly array $config) - { - } + return new self(ShlinkConfig::fromRawConfig(new class($config) implements RawConfigInterface { + public function __construct(private readonly array $config) {} public function baseUrl(): string { diff --git a/src/Config/EnvShlinkConfig.php b/src/Config/EnvShlinkConfig.php index 7f29ba0..6bcf853 100644 --- a/src/Config/EnvShlinkConfig.php +++ b/src/Config/EnvShlinkConfig.php @@ -16,9 +16,7 @@ public const API_KEY_ENV_VAR = 'SHLINK_API_KEY'; public const VERSION_ENV_VAR = 'SHLINK_API_VERSION'; - private function __construct(private ShlinkConfigInterface $wrapped) - { - } + private function __construct(private ShlinkConfigInterface $wrapped) {} /** * @throws InvalidConfigException @@ -26,10 +24,8 @@ private function __construct(private ShlinkConfigInterface $wrapped) public static function fromEnv(): self { $env = getenv(); - return new self(ShlinkConfig::fromRawConfig(new class ($env) implements RawConfigInterface { - public function __construct(private readonly array $env) - { - } + return new self(ShlinkConfig::fromRawConfig(new class($env) implements RawConfigInterface { + public function __construct(private readonly array $env) {} public function baseUrl(): string { diff --git a/src/Config/ShlinkConfig.php b/src/Config/ShlinkConfig.php index 517eb44..3abf3a6 100644 --- a/src/Config/ShlinkConfig.php +++ b/src/Config/ShlinkConfig.php @@ -9,9 +9,7 @@ final readonly class ShlinkConfig implements ShlinkConfigInterface { - private function __construct(private string $baseUrl, private string $apiKey, private ApiVersion $version) - { - } + private function __construct(private string $baseUrl, private string $apiKey, private ApiVersion $version) {} public static function fromBaseUrlAndApiKey(string $baseUrl, string $apiKey): ShlinkConfigInterface { diff --git a/src/Domains/DomainsClient.php b/src/Domains/DomainsClient.php index 29be90d..548d6b8 100644 --- a/src/Domains/DomainsClient.php +++ b/src/Domains/DomainsClient.php @@ -14,9 +14,7 @@ readonly class DomainsClient implements DomainsClientInterface { - public function __construct(private HttpClientInterface $httpClient) - { - } + public function __construct(private HttpClientInterface $httpClient) {} /** * @inheritDoc diff --git a/src/Domains/Model/Domain.php b/src/Domains/Model/Domain.php index ca08152..bb24d9b 100644 --- a/src/Domains/Model/Domain.php +++ b/src/Domains/Model/Domain.php @@ -6,9 +6,7 @@ final readonly class Domain { - private function __construct(public string $domain, public bool $isDefault, public DomainRedirects $redirects) - { - } + private function __construct(public string $domain, public bool $isDefault, public DomainRedirects $redirects) {} public static function fromArray(array $payload): self { diff --git a/src/Domains/Model/DomainRedirects.php b/src/Domains/Model/DomainRedirects.php index 9a3ac0f..319d9f0 100644 --- a/src/Domains/Model/DomainRedirects.php +++ b/src/Domains/Model/DomainRedirects.php @@ -10,8 +10,7 @@ private function __construct( public string|null $baseUrlRedirect, public string|null $regularNotFoundRedirect, public string|null $invalidShortUrlRedirect, - ) { - } + ) {} public static function fromArray(array $payload): self { diff --git a/src/Domains/Model/DomainRedirectsConfig.php b/src/Domains/Model/DomainRedirectsConfig.php index 127f53c..28da2fc 100644 --- a/src/Domains/Model/DomainRedirectsConfig.php +++ b/src/Domains/Model/DomainRedirectsConfig.php @@ -8,9 +8,7 @@ final class DomainRedirectsConfig implements JsonSerializable { - private function __construct(private array $payload = []) - { - } + private function __construct(private array $payload = []) {} public static function forDomain(string $domain): self { diff --git a/src/Exception/ExceptionInterface.php b/src/Exception/ExceptionInterface.php index 302e759..fa351c4 100644 --- a/src/Exception/ExceptionInterface.php +++ b/src/Exception/ExceptionInterface.php @@ -6,6 +6,4 @@ use Throwable; -interface ExceptionInterface extends Throwable -{ -} +interface ExceptionInterface extends Throwable {} diff --git a/src/Http/ApiVersion.php b/src/Http/ApiVersion.php index 730bab5..b7e261c 100644 --- a/src/Http/ApiVersion.php +++ b/src/Http/ApiVersion.php @@ -1,5 +1,7 @@ ! in_array($key, self::STANDARD_PROBLEM_DETAILS_PROPS, true), + static fn (string $key) => !in_array($key, self::STANDARD_PROBLEM_DETAILS_PROPS, true), ARRAY_FILTER_USE_KEY, ); diff --git a/src/Http/HttpClient.php b/src/Http/HttpClient.php index f2811b5..593a1cc 100644 --- a/src/Http/HttpClient.php +++ b/src/Http/HttpClient.php @@ -29,8 +29,7 @@ public function __construct( private StreamFactoryInterface $streamFactory, private ShlinkConfigInterface $config, private HttpDebuggerInterface|null $debugger = null, - ) { - } + ) {} /** * @throws HttpException @@ -63,16 +62,16 @@ private function callShlink( array $query = [], ): array { $uri = sprintf('%s/rest/v%s%s', $this->config->baseUrl(), $this->config->version()->value, $path); - if (! empty($query)) { + if (!empty($query)) { $uri = sprintf('%s?%s', $uri, http_build_query($query)); } $req = $this->requestFactory->createRequest($method, $uri) - ->withHeader('X-Api-Key', $this->config->apiKey()); + ->withHeader('X-Api-Key', $this->config->apiKey()); if ($body !== null) { $req = $req->withHeader('Content-Type', 'application/json') - ->withBody($this->streamFactory->createStream(json_encode($body, JSON_THROW_ON_ERROR))); + ->withBody($this->streamFactory->createStream(json_encode($body, JSON_THROW_ON_ERROR))); } $this->debugger?->debugRequest($req); diff --git a/src/Model/ListEndpointIterator.php b/src/Model/ListEndpointIterator.php index 0da7383..9a0a5dd 100644 --- a/src/Model/ListEndpointIterator.php +++ b/src/Model/ListEndpointIterator.php @@ -44,7 +44,7 @@ private function getFullList(): iterable } $isLastPage = $currentPage < 0 || $currentPage === $this->currentPagination['pagesCount']; - if (! $isLastPage) { + if (!$isLastPage) { $this->loadPage($currentPage + 1); yield from $this->getFullList(); } @@ -52,7 +52,7 @@ private function getFullList(): iterable private function calculateIndex(int $index, int $currentPage): int { - return ($currentPage - 1) * $this->itemsPerPage + $index; + return (($currentPage - 1) * $this->itemsPerPage) + $index; } public function count(): int diff --git a/src/RedirectRules/Model/RedirectCondition.php b/src/RedirectRules/Model/RedirectCondition.php index cbf8d6f..c405ec2 100644 --- a/src/RedirectRules/Model/RedirectCondition.php +++ b/src/RedirectRules/Model/RedirectCondition.php @@ -15,8 +15,7 @@ private function __construct( public string|null $matchValue = null, public string|null $matchKey = null, private string|null $originalType = null, - ) { - } + ) {} public static function forQueryParam(string $param, string $value): self { @@ -77,7 +76,7 @@ public static function fromArray(array $payload): self $originalType = $payload['type'] ?? ''; return new self( type: RedirectConditionType::tryFrom($originalType) ?? RedirectConditionType::UNKNOWN, - matchValue: $payload['matchValue'] ?? null, + matchValue: $payload['matchValue'] ?? null, matchKey: $payload['matchKey'] ?? null, originalType: $originalType, ); diff --git a/src/RedirectRules/Model/RedirectConditionType.php b/src/RedirectRules/Model/RedirectConditionType.php index 4936409..b75de86 100644 --- a/src/RedirectRules/Model/RedirectConditionType.php +++ b/src/RedirectRules/Model/RedirectConditionType.php @@ -1,5 +1,7 @@ RedirectCondition::fromArray($condition), + RedirectCondition::fromArray(...), $payload['conditions'] ?? [], ), ); diff --git a/src/RedirectRules/Model/RedirectRuleData.php b/src/RedirectRules/Model/RedirectRuleData.php index 993c6bb..b12898a 100644 --- a/src/RedirectRules/Model/RedirectRuleData.php +++ b/src/RedirectRules/Model/RedirectRuleData.php @@ -11,9 +11,7 @@ /** * @param RedirectCondition[] $conditions */ - private function __construct(public string $longUrl, public array $conditions) - { - } + private function __construct(public string $longUrl, public array $conditions) {} public static function forLongUrl(string $longUrl): self { diff --git a/src/RedirectRules/Model/RedirectRulesList.php b/src/RedirectRules/Model/RedirectRulesList.php index 95755e3..76c33cc 100644 --- a/src/RedirectRules/Model/RedirectRulesList.php +++ b/src/RedirectRules/Model/RedirectRulesList.php @@ -14,16 +14,14 @@ /** * @param RedirectRule[] $redirectRules */ - private function __construct(public string $defaultLongUrl, public array $redirectRules) - { - } + private function __construct(public string $defaultLongUrl, public array $redirectRules) {} public static function fromArray(array $payload): self { return new self( defaultLongUrl: $payload['defaultLongUrl'] ?? '', redirectRules: array_map( - static fn (array $rule) => RedirectRule::fromArray($rule), + RedirectRule::fromArray(...), $payload['redirectRules'] ?? [], ), ); diff --git a/src/RedirectRules/Model/SetRedirectRules.php b/src/RedirectRules/Model/SetRedirectRules.php index 39cbdc3..07fae6f 100644 --- a/src/RedirectRules/Model/SetRedirectRules.php +++ b/src/RedirectRules/Model/SetRedirectRules.php @@ -15,9 +15,7 @@ /** * @param array $rules */ - private function __construct(private array $rules) - { - } + private function __construct(private array $rules) {} public static function fromScratch(): self { diff --git a/src/RedirectRules/RedirectRulesClient.php b/src/RedirectRules/RedirectRulesClient.php index f7f4b06..298d5a0 100644 --- a/src/RedirectRules/RedirectRulesClient.php +++ b/src/RedirectRules/RedirectRulesClient.php @@ -17,9 +17,7 @@ readonly class RedirectRulesClient implements RedirectRulesClientInterface { - public function __construct(private HttpClientInterface $httpClient) - { - } + public function __construct(private HttpClientInterface $httpClient) {} public function getShortUrlRedirectRules(ShortUrlIdentifier $identifier): RedirectRulesList { diff --git a/src/ShlinkClient.php b/src/ShlinkClient.php index d07ad31..eee2426 100644 --- a/src/ShlinkClient.php +++ b/src/ShlinkClient.php @@ -42,8 +42,7 @@ public function __construct( private TagsClientInterface $tagsClient, private DomainsClientInterface $domainsClient, private RedirectRulesClientInterface $redirectRulesClient, - ) { - } + ) {} /** * @inheritDoc diff --git a/src/ShortUrls/Model/Device.php b/src/ShortUrls/Model/Device.php index a263fb2..0f8ae7d 100644 --- a/src/ShortUrls/Model/Device.php +++ b/src/ShortUrls/Model/Device.php @@ -1,5 +1,7 @@ ShortUrl::fromArray($value), self::ITEMS_PER_PAGE); + parent::__construct($pageLoader, ShortUrl::fromArray(...), self::ITEMS_PER_PAGE); } /** diff --git a/src/ShortUrls/ShortUrlsClient.php b/src/ShortUrls/ShortUrlsClient.php index 45e0d8e..1b6c0fc 100644 --- a/src/ShortUrls/ShortUrlsClient.php +++ b/src/ShortUrls/ShortUrlsClient.php @@ -22,9 +22,7 @@ readonly class ShortUrlsClient implements ShortUrlsClientInterface { - public function __construct(private HttpClientInterface $httpClient) - { - } + public function __construct(private HttpClientInterface $httpClient) {} public function listShortUrls(): ShortUrlsList { diff --git a/src/Tags/Model/TagRenaming.php b/src/Tags/Model/TagRenaming.php index 75c1c8d..4978ac7 100644 --- a/src/Tags/Model/TagRenaming.php +++ b/src/Tags/Model/TagRenaming.php @@ -8,9 +8,7 @@ final readonly class TagRenaming implements JsonSerializable { - private function __construct(private array $payload) - { - } + private function __construct(private array $payload) {} public static function fromOldNameAndNewName(string $oldName, string $newName): self { diff --git a/src/Tags/Model/TagWithStats.php b/src/Tags/Model/TagWithStats.php index d1c66d4..8f2c5a0 100644 --- a/src/Tags/Model/TagWithStats.php +++ b/src/Tags/Model/TagWithStats.php @@ -8,9 +8,7 @@ final readonly class TagWithStats { - private function __construct(public string $tag, public int $shortUrlsCount, public VisitsSummary $visitsSummary) - { - } + private function __construct(public string $tag, public int $shortUrlsCount, public VisitsSummary $visitsSummary) {} public static function fromArray(array $payload): self { diff --git a/src/Tags/Model/TagsFilter.php b/src/Tags/Model/TagsFilter.php index b06b78f..008baaa 100644 --- a/src/Tags/Model/TagsFilter.php +++ b/src/Tags/Model/TagsFilter.php @@ -12,9 +12,7 @@ final class TagsFilter implements ArraySerializable { - private function __construct(private array $query = []) - { - } + private function __construct(private array $query = []) {} public static function create(): self { @@ -55,7 +53,7 @@ public function shouldPaginateRequest(): bool // no matter the size of the page. Because of that, when ordering by those fields, it's better to load the // whole dataset at once, until that issue is fixed. - if (! isset($this->query['orderBy'])) { + if (!isset($this->query['orderBy'])) { return true; } @@ -65,6 +63,6 @@ public function shouldPaginateRequest(): bool TagsListOrderField::VISITS_COUNT->value, ]; - return ! in_array($field, $orderFieldsThatShouldNotPaginate, true); + return !in_array($field, $orderFieldsThatShouldNotPaginate, true); } } diff --git a/src/Tags/Model/TagsMode.php b/src/Tags/Model/TagsMode.php index 5418715..41f6faa 100644 --- a/src/Tags/Model/TagsMode.php +++ b/src/Tags/Model/TagsMode.php @@ -1,5 +1,7 @@ $deletedVisits */ - private function __construct(public int $deletedVisits) - { - } + private function __construct(public int $deletedVisits) {} public static function fromArray(array $payload): self { diff --git a/src/Visits/Model/VisitsFilterPayloadTrait.php b/src/Visits/Model/VisitsFilterPayloadTrait.php index 74cfece..11d5b39 100644 --- a/src/Visits/Model/VisitsFilterPayloadTrait.php +++ b/src/Visits/Model/VisitsFilterPayloadTrait.php @@ -8,9 +8,7 @@ trait VisitsFilterPayloadTrait { - private function __construct(private array $query = []) - { - } + private function __construct(private array $query = []) {} public static function create(): self { diff --git a/src/Visits/Model/VisitsList.php b/src/Visits/Model/VisitsList.php index b90b1a0..b66ed8e 100644 --- a/src/Visits/Model/VisitsList.php +++ b/src/Visits/Model/VisitsList.php @@ -30,7 +30,7 @@ private function __construct(Closure $visitsLoader, Closure $itemMapper) */ public static function forTupleLoader(Closure $visitsLoader): self { - return new self($visitsLoader, static fn (array $value) => Visit::fromArray($value)); + return new self($visitsLoader, Visit::fromArray(...)); } /** @@ -39,6 +39,6 @@ public static function forTupleLoader(Closure $visitsLoader): self */ public static function forOrphanVisitsTupleLoader(Closure $visitsLoader): self { - return new self($visitsLoader, static fn (array $value) => OrphanVisit::fromArray($value)); + return new self($visitsLoader, OrphanVisit::fromArray(...)); } } diff --git a/src/Visits/Model/VisitsOverview.php b/src/Visits/Model/VisitsOverview.php index c56d477..56c865d 100644 --- a/src/Visits/Model/VisitsOverview.php +++ b/src/Visits/Model/VisitsOverview.php @@ -8,9 +8,7 @@ final readonly class VisitsOverview implements Countable { - private function __construct(public VisitsSummary $nonOrphanVisits, public VisitsSummary $orphanVisits) - { - } + private function __construct(public VisitsSummary $nonOrphanVisits, public VisitsSummary $orphanVisits) {} public static function fromArray(array $payload): self { diff --git a/src/Visits/Model/VisitsSummary.php b/src/Visits/Model/VisitsSummary.php index 57c84c1..68a0ae9 100644 --- a/src/Visits/Model/VisitsSummary.php +++ b/src/Visits/Model/VisitsSummary.php @@ -11,9 +11,7 @@ * @param int<0, max> $nonBots * @param int<0, max> $bots */ - private function __construct(public int $total, public int $nonBots, public int $bots) - { - } + private function __construct(public int $total, public int $nonBots, public int $bots) {} public static function fromArray(array $payload): self { diff --git a/src/Visits/VisitsClient.php b/src/Visits/VisitsClient.php index ef30e16..b6d3a79 100644 --- a/src/Visits/VisitsClient.php +++ b/src/Visits/VisitsClient.php @@ -23,9 +23,7 @@ readonly class VisitsClient implements VisitsClientInterface { - public function __construct(private HttpClientInterface $httpClient) - { - } + public function __construct(private HttpClientInterface $httpClient) {} public function getVisitsOverview(): VisitsOverview { diff --git a/test-integration/Tags/TagsClientTest.php b/test-integration/Tags/TagsClientTest.php index e68378d..18de7fe 100644 --- a/test-integration/Tags/TagsClientTest.php +++ b/test-integration/Tags/TagsClientTest.php @@ -22,9 +22,10 @@ protected function setUp(): void { $this->client = new TagsClient(self::httpClient()); - self::shlinkClient()->createShortUrl( - ShortUrlCreation::forLongUrl('https://example.com')->withTags(...self::BASE_TAGS), - ); + self::shlinkClient() + ->createShortUrl( + ShortUrlCreation::forLongUrl('https://example.com')->withTags(...self::BASE_TAGS), + ); } #[Test] diff --git a/test/Builder/SingletonShlinkClientBuilderTest.php b/test/Builder/SingletonShlinkClientBuilderTest.php index 99b2a2f..0c22550 100644 --- a/test/Builder/SingletonShlinkClientBuilderTest.php +++ b/test/Builder/SingletonShlinkClientBuilderTest.php @@ -24,7 +24,7 @@ class SingletonShlinkClientBuilderTest extends TestCase use ClientBuilderMethodsProviderTrait; private SingletonShlinkClientBuilder $builder; - private MockObject & ShlinkClientBuilderInterface $wrapped; + private MockObject&ShlinkClientBuilderInterface $wrapped; public function setUp(): void { @@ -38,15 +38,19 @@ public function setUp(): void #[Test, DataProvider('provideMethods')] public function buildClientReturnsAlwaysNewInstances(string $method): void { - $this->wrapped->expects($this->exactly(2))->method($method)->with( - $this->isInstanceOf(ShlinkConfigInterface::class), - )->willReturn(new ShlinkClient( - $this->createStub(ShortUrlsClientInterface::class), - $this->createStub(VisitsClientInterface::class), - $this->createStub(TagsClientInterface::class), - $this->createStub(DomainsClientInterface::class), - $this->createStub(RedirectRulesClientInterface::class), - )); + $this->wrapped + ->expects($this->exactly(2)) + ->method($method) + ->with( + $this->isInstanceOf(ShlinkConfigInterface::class), + ) + ->willReturn(new ShlinkClient( + $this->createStub(ShortUrlsClientInterface::class), + $this->createStub(VisitsClientInterface::class), + $this->createStub(TagsClientInterface::class), + $this->createStub(DomainsClientInterface::class), + $this->createStub(RedirectRulesClientInterface::class), + )); $configOne = ShlinkConfig::fromBaseUrlAndApiKey('foo', 'bar'); $instance1 = $this->builder->{$method}($configOne); diff --git a/test/Config/ArrayShlinkConfigTest.php b/test/Config/ArrayShlinkConfigTest.php index d0518d3..775f8a0 100644 --- a/test/Config/ArrayShlinkConfigTest.php +++ b/test/Config/ArrayShlinkConfigTest.php @@ -26,17 +26,21 @@ public function exceptionIsThrownIfProvidedDataIsInvalid( public static function provideInvalidData(): iterable { - $standardMessage = 'Provided array is missing "baseUrl" and/or "apiKey" props, or their values are invalid. ' + $standardMessage = + 'Provided array is missing "baseUrl" and/or "apiKey" props, or their values are invalid. ' . 'Make sure both are set with strings.'; yield 'both missing' => [[], $standardMessage]; yield 'missing api key' => [[ArrayShlinkConfig::BASE_URL_PROP => 'foo'], $standardMessage]; yield 'missing base url' => [[ArrayShlinkConfig::API_KEY_PROP => 'bar'], $standardMessage]; - yield 'invalid version' => [[ - ArrayShlinkConfig::BASE_URL_PROP => 'foo', - ArrayShlinkConfig::API_KEY_PROP => 'bar', - ArrayShlinkConfig::VERSION_PROP => '2', - ], 'Provided version "2" is invalid. Expected one of ["3"]']; + yield 'invalid version' => [ + [ + ArrayShlinkConfig::BASE_URL_PROP => 'foo', + ArrayShlinkConfig::API_KEY_PROP => 'bar', + ArrayShlinkConfig::VERSION_PROP => '2', + ], + 'Provided version "2" is invalid. Expected one of ["3"]', + ]; } #[Test] diff --git a/test/Config/EnvShlinkConfigTest.php b/test/Config/EnvShlinkConfigTest.php index 05bdc05..3219904 100644 --- a/test/Config/EnvShlinkConfigTest.php +++ b/test/Config/EnvShlinkConfigTest.php @@ -41,7 +41,8 @@ public static function provideWrongEnvSetUps(): iterable putenv(sprintf('%s=%s', $key, $value)); } }; - $standardMessage = 'Either "SHLINK_BASE_URL" and/or "SHLINK_API_KEY" env vars are missing. ' + $standardMessage = + 'Either "SHLINK_BASE_URL" and/or "SHLINK_API_KEY" env vars are missing. ' . 'Make sure both are properly set.'; yield 'no env vars' => [$buildSetUpWithEnvVars(), $standardMessage]; @@ -53,11 +54,14 @@ public static function provideWrongEnvSetUps(): iterable $buildSetUpWithEnvVars([EnvShlinkConfig::BASE_URL_ENV_VAR => 'SOME_VALUE']), $standardMessage, ]; - yield 'invalid api version' => [$buildSetUpWithEnvVars([ - EnvShlinkConfig::BASE_URL_ENV_VAR => 'SOME_VALUE', - EnvShlinkConfig::API_KEY_ENV_VAR => 'SOME_VALUE', - EnvShlinkConfig::VERSION_ENV_VAR => '4', - ]), 'Provided version "4" is invalid. Expected one of ["3"]']; + yield 'invalid api version' => [ + $buildSetUpWithEnvVars([ + EnvShlinkConfig::BASE_URL_ENV_VAR => 'SOME_VALUE', + EnvShlinkConfig::API_KEY_ENV_VAR => 'SOME_VALUE', + EnvShlinkConfig::VERSION_ENV_VAR => '4', + ]), + 'Provided version "4" is invalid. Expected one of ["3"]', + ]; } #[Test] diff --git a/test/Domains/DomainsClientTest.php b/test/Domains/DomainsClientTest.php index b0d70cc..7b1f448 100644 --- a/test/Domains/DomainsClientTest.php +++ b/test/Domains/DomainsClientTest.php @@ -22,7 +22,7 @@ class DomainsClientTest extends TestCase { private DomainsClient $domainsClient; - private MockObject & HttpClientInterface $httpClient; + private MockObject&HttpClientInterface $httpClient; public function setUp(): void { @@ -63,9 +63,13 @@ public function expectedDomainsAreReturnedOnList(): void ], ]; - $this->httpClient->expects($this->once())->method('getFromShlink')->with('/domains')->willReturn([ - 'domains' => ['data' => $payload], - ]); + $this->httpClient + ->expects($this->once()) + ->method('getFromShlink') + ->with('/domains') + ->willReturn([ + 'domains' => ['data' => $payload], + ]); $result = $this->domainsClient->listDomains(); $count = 0; @@ -99,15 +103,19 @@ public function configureDomainRedirectsSendsExpectedRequestAndReceivesExpectedR ->removingBaseUrlRedirect() ->removingInvalidShortUrlRedirect(); - $this->httpClient->expects($this->once())->method('callShlinkWithBody')->with( - '/domains/redirects', - 'PATCH', - $config, - )->willReturn([ - DomainRedirectProps::BASE_URL->value => null, - DomainRedirectProps::REGULAR_NOT_FOUND->value => 'somewhere.com', - DomainRedirectProps::INVALID_SHORT_URL->value => null, - ]); + $this->httpClient + ->expects($this->once()) + ->method('callShlinkWithBody') + ->with( + '/domains/redirects', + 'PATCH', + $config, + ) + ->willReturn([ + DomainRedirectProps::BASE_URL->value => null, + DomainRedirectProps::REGULAR_NOT_FOUND->value => 'somewhere.com', + DomainRedirectProps::INVALID_SHORT_URL->value => null, + ]); $result = $this->domainsClient->configureDomainRedirects($config); @@ -133,8 +141,8 @@ public function configureDomainRedirectsThrowsProperExceptionIfSomethingGoesWron public static function provideExceptions(): iterable { yield 'no type' => [HttpException::fromPayload([]), HttpException::class]; - yield 'not expected type' => [HttpException::fromPayload(['type' => 'something else']), HttpException::class]; - yield 'INVALID_ARGUMENT' => [ + yield 'not expected type' => [HttpException::fromPayload(['type' => 'something else']), HttpException::class]; + yield 'INVALID_ARGUMENT' => [ HttpException::fromPayload(['type' => ErrorType::INVALID_DATA->value]), InvalidDataException::class, ]; diff --git a/test/Domains/Exception/DomainNotFoundExceptionTest.php b/test/Domains/Exception/DomainNotFoundExceptionTest.php index e4af6ed..c322cdc 100644 --- a/test/Domains/Exception/DomainNotFoundExceptionTest.php +++ b/test/Domains/Exception/DomainNotFoundExceptionTest.php @@ -29,14 +29,24 @@ public function exceptionIsProperlyCreated( public static function provideExceptions(): iterable { yield [HttpException::fromPayload([]), '', '', -1]; - yield [HttpException::fromPayload([ - 'detail' => $message = 'This is the message', - 'status' => $code = 400, - ]), '', $message, $code]; - yield [HttpException::fromPayload([ - 'detail' => $message = 'This is the message again', - 'status' => $code = 404, - 'authority' => $authority = 'authority', - ]), $authority, $message, $code]; + yield [ + HttpException::fromPayload([ + 'detail' => $message = 'This is the message', + 'status' => $code = 400, + ]), + '', + $message, + $code, + ]; + yield [ + HttpException::fromPayload([ + 'detail' => $message = 'This is the message again', + 'status' => $code = 404, + 'authority' => $authority = 'authority', + ]), + $authority, + $message, + $code, + ]; } } diff --git a/test/Domains/Model/DomainRedirectsConfigTest.php b/test/Domains/Model/DomainRedirectsConfigTest.php index 9b8693f..bd1f8f7 100644 --- a/test/Domains/Model/DomainRedirectsConfigTest.php +++ b/test/Domains/Model/DomainRedirectsConfigTest.php @@ -22,9 +22,9 @@ public function payloadIsBuiltAsExpected(callable $createConfig, array $expected public static function provideConfigs(): iterable { - yield [fn () => DomainRedirectsConfig::forDomain('foo.com'), ['domain' => 'foo.com']]; + yield [static fn () => DomainRedirectsConfig::forDomain('foo.com'), ['domain' => 'foo.com']]; yield [ - fn () => DomainRedirectsConfig::forDomain('foo.com') + static fn () => DomainRedirectsConfig::forDomain('foo.com') ->withRegularNotFoundRedirect('somewhere.com'), [ 'domain' => 'foo.com', @@ -32,7 +32,7 @@ public static function provideConfigs(): iterable ], ]; yield [ - fn () => DomainRedirectsConfig::forDomain('bar.com') + static fn () => DomainRedirectsConfig::forDomain('bar.com') ->withRegularNotFoundRedirect('foo.com') ->removingBaseUrlRedirect(), [ @@ -42,7 +42,7 @@ public static function provideConfigs(): iterable ], ]; yield [ - fn () => DomainRedirectsConfig::forDomain('bar.com') + static fn () => DomainRedirectsConfig::forDomain('bar.com') ->withRegularNotFoundRedirect('foo.net') ->withInvalidShortUrlRedirect('something.com') ->removingBaseUrlRedirect(), @@ -54,7 +54,7 @@ public static function provideConfigs(): iterable ], ]; yield [ - fn () => DomainRedirectsConfig::forDomain('baz.com') + static fn () => DomainRedirectsConfig::forDomain('baz.com') ->removingBaseUrlRedirect() ->removingRegularNotFoundRedirect() ->removingInvalidShortUrlRedirect(), @@ -66,7 +66,7 @@ public static function provideConfigs(): iterable ], ]; yield [ - fn () => DomainRedirectsConfig::forDomain('foobarbaz.com') + static fn () => DomainRedirectsConfig::forDomain('foobarbaz.com') ->withRegularNotFoundRedirect('foo.net') ->withInvalidShortUrlRedirect('something.com') ->withBaseUrlRedirect('base-redirect.com'), diff --git a/test/Http/Exception/HttpExceptionTest.php b/test/Http/Exception/HttpExceptionTest.php index 1252876..1c9ab09 100644 --- a/test/Http/Exception/HttpExceptionTest.php +++ b/test/Http/Exception/HttpExceptionTest.php @@ -41,7 +41,7 @@ public function exceptionIsCreatedAsExpectedFromResponse( array $expectedAdditional, ): void { $e = HttpException::fromNonSuccessfulResponse( - (new Response())->withBody(Utils::streamFor(json_encode($payload, JSON_THROW_ON_ERROR))), + new Response()->withBody(Utils::streamFor(json_encode($payload, JSON_THROW_ON_ERROR))), ); $this->runAssertions($e, $expectedType, $expectedTitle, $expectedDetail, $expectedStatus, $expectedAdditional); } diff --git a/test/Http/HttpClientTest.php b/test/Http/HttpClientTest.php index 03d017c..8cec1c5 100644 --- a/test/Http/HttpClientTest.php +++ b/test/Http/HttpClientTest.php @@ -26,19 +26,23 @@ class HttpClientTest extends TestCase { private HttpClient $httpClient; - private MockObject & ClientInterface $client; + private MockObject&ClientInterface $client; public function setUp(): void { $this->client = $this->createMock(ClientInterface::class); $requestFactory = $this->createStub(RequestFactoryInterface::class); - $requestFactory->method('createRequest')->willReturnCallback( - fn (string $method, string|UriInterface $uri) => new Request($method, $uri), - ); + $requestFactory + ->method('createRequest') + ->willReturnCallback( + static fn (string $method, string|UriInterface $uri) => new Request($method, $uri), + ); $streamFactory = $this->createStub(StreamFactoryInterface::class); - $streamFactory->method('createStream')->willReturnCallback(fn (string $content) => Utils::streamFor($content)); + $streamFactory + ->method('createStream') + ->willReturnCallback(Utils::streamFor(...)); $this->httpClient = new HttpClient( $this->client, @@ -54,16 +58,20 @@ public function getFromShlinkSendsExpectedRequest( array|ArraySerializable $query, string $expectedUri, ): void { - $this->client->expects($this->once())->method('sendRequest')->with($this->callback( - function (RequestInterface $req) use ($expectedUri) { - Assert::assertEquals($expectedUri, $req->getUri()->__toString()); - Assert::assertEquals('GET', $req->getMethod()); - Assert::assertTrue($req->hasHeader('X-Api-Key')); - Assert::assertEquals('123', $req->getHeaderLine('X-Api-Key')); - - return true; - }, - ))->willReturn(new Response(200, [], '{}')); + $this->client + ->expects($this->once()) + ->method('sendRequest') + ->with($this->callback( + static function (RequestInterface $req) use ($expectedUri) { + Assert::assertEquals($expectedUri, $req->getUri()->__toString()); + Assert::assertEquals('GET', $req->getMethod()); + Assert::assertTrue($req->hasHeader('X-Api-Key')); + Assert::assertEquals('123', $req->getHeaderLine('X-Api-Key')); + + return true; + }, + )) + ->willReturn(new Response(200, [], '{}')); $this->httpClient->getFromShlink($path, $query); } @@ -87,7 +95,10 @@ public function toArray(): array #[Test, DataProvider('provideNonSuccessfulStatuses')] public function nonSuccessfulResponseResultsInException(int $status): void { - $this->client->expects($this->once())->method('sendRequest')->willReturn(new Response($status, [], '{}')); + $this->client + ->expects($this->once()) + ->method('sendRequest') + ->willReturn(new Response($status, [], '{}')); $this->expectException(HttpException::class); @@ -107,9 +118,12 @@ public static function provideNonSuccessfulStatuses(): iterable #[Test, DataProvider('provideSuccessfulStatuses')] public function returnsExpectedResultBasedOnResponseStatus(int $status, array $expectedResult): void { - $this->client->expects($this->once())->method('sendRequest')->willReturn( - new Response($status, [], '{"foo": "bar"}'), - ); + $this->client + ->expects($this->once()) + ->method('sendRequest') + ->willReturn( + new Response($status, [], '{"foo": "bar"}'), + ); $result = $this->httpClient->getFromShlink(''); @@ -130,16 +144,20 @@ public function callShlinkWithBodySendsExpectedRequest( array|JsonSerializable $body, string $expectedBody, ): void { - $this->client->expects($this->once())->method('sendRequest')->with( - $this->callback(function (RequestInterface $req) use ($expectedBody, $method) { - Assert::assertEquals($expectedBody, $req->getBody()->__toString()); - Assert::assertEquals($method, $req->getMethod()); - Assert::assertTrue($req->hasHeader('X-Api-Key')); - Assert::assertEquals('123', $req->getHeaderLine('X-Api-Key')); - - return true; - }), - )->willReturn(new Response(200, [], '{}')); + $this->client + ->expects($this->once()) + ->method('sendRequest') + ->with( + $this->callback(static function (RequestInterface $req) use ($expectedBody, $method) { + Assert::assertEquals($expectedBody, $req->getBody()->__toString()); + Assert::assertEquals($method, $req->getMethod()); + Assert::assertTrue($req->hasHeader('X-Api-Key')); + Assert::assertEquals('123', $req->getHeaderLine('X-Api-Key')); + + return true; + }), + ) + ->willReturn(new Response(200, [], '{}')); $this->httpClient->callShlinkWithBody('/foo/bar', $method, $body); } diff --git a/test/RedirectRules/Model/RedirectRuleDataTest.php b/test/RedirectRules/Model/RedirectRuleDataTest.php index c753cc1..febc77a 100644 --- a/test/RedirectRules/Model/RedirectRuleDataTest.php +++ b/test/RedirectRules/Model/RedirectRuleDataTest.php @@ -27,14 +27,17 @@ public function creationFromRedirectRule(): void ]); $data = RedirectRuleData::fromRedirectRule($redirectRule); - self::assertEquals([ - 'longUrl' => 'https://example.com', - 'conditions' => [ - RedirectCondition::fromArray([]), - RedirectCondition::fromArray([]), - RedirectCondition::fromArray([]), + self::assertEquals( + [ + 'longUrl' => 'https://example.com', + 'conditions' => [ + RedirectCondition::fromArray([]), + RedirectCondition::fromArray([]), + RedirectCondition::fromArray([]), + ], ], - ], $data->jsonSerialize()); + $data->jsonSerialize(), + ); } #[Test] diff --git a/test/RedirectRules/Model/SetRedirectRulesTest.php b/test/RedirectRules/Model/SetRedirectRulesTest.php index 2ca94e6..14828bd 100644 --- a/test/RedirectRules/Model/SetRedirectRulesTest.php +++ b/test/RedirectRules/Model/SetRedirectRulesTest.php @@ -55,35 +55,38 @@ public function creationFromRedirectRulesList(): void $setRules = SetRedirectRules::fromRedirectRulesList($list); - self::assertEquals([ - 'redirectRules' => [ - [ - 'longUrl' => 'https://example.com/android', - 'conditions' => [ - [ - 'type' => RedirectConditionType::DEVICE->value, - 'matchValue' => Device::ANDROID->value, - 'matchKey' => null, + self::assertEquals( + [ + 'redirectRules' => [ + [ + 'longUrl' => 'https://example.com/android', + 'conditions' => [ + [ + 'type' => RedirectConditionType::DEVICE->value, + 'matchValue' => Device::ANDROID->value, + 'matchKey' => null, + ], ], ], - ], - [ - 'longUrl' => 'https://example.com/freanch-and-foo-bar-query', - 'conditions' => [ - [ - 'type' => RedirectConditionType::LANGUAGE->value, - 'matchValue' => 'fr', - 'matchKey' => null, - ], - [ - 'type' => RedirectConditionType::QUERY_PARAM->value, - 'matchValue' => 'bar', - 'matchKey' => 'foo', + [ + 'longUrl' => 'https://example.com/freanch-and-foo-bar-query', + 'conditions' => [ + [ + 'type' => RedirectConditionType::LANGUAGE->value, + 'matchValue' => 'fr', + 'matchKey' => null, + ], + [ + 'type' => RedirectConditionType::QUERY_PARAM->value, + 'matchValue' => 'bar', + 'matchKey' => 'foo', + ], ], ], ], ], - ], json_decode((string) json_encode($setRules->jsonSerialize()), associative: true)); + json_decode((string) json_encode($setRules->jsonSerialize()), associative: true), + ); } #[Test] @@ -104,28 +107,37 @@ public function rulesCanBeAddedOrRemoved(): void $setRules = SetRedirectRules::fromScratch() ->withPushedRule(RedirectRuleData::forLongUrl('https://example.com/first')) ->withPushedRule(RedirectRuleData::forLongUrl('https://example.com/second')); - self::assertEquals([ - 'redirectRules' => [ - RedirectRuleData::forLongUrl('https://example.com/first'), - RedirectRuleData::forLongUrl('https://example.com/second'), + self::assertEquals( + [ + 'redirectRules' => [ + RedirectRuleData::forLongUrl('https://example.com/first'), + RedirectRuleData::forLongUrl('https://example.com/second'), + ], ], - ], $setRules->jsonSerialize()); + $setRules->jsonSerialize(), + ); $setRules = $setRules->withRule(2, RedirectRuleData::forLongUrl('https://example.com/third')); - self::assertEquals([ - 'redirectRules' => [ - RedirectRuleData::forLongUrl('https://example.com/first'), - RedirectRuleData::forLongUrl('https://example.com/third'), - RedirectRuleData::forLongUrl('https://example.com/second'), + self::assertEquals( + [ + 'redirectRules' => [ + RedirectRuleData::forLongUrl('https://example.com/first'), + RedirectRuleData::forLongUrl('https://example.com/third'), + RedirectRuleData::forLongUrl('https://example.com/second'), + ], ], - ], $setRules->jsonSerialize()); + $setRules->jsonSerialize(), + ); $setRules = $setRules->withoutRule(1); - self::assertEquals([ - 'redirectRules' => [ - RedirectRuleData::forLongUrl('https://example.com/third'), - RedirectRuleData::forLongUrl('https://example.com/second'), + self::assertEquals( + [ + 'redirectRules' => [ + RedirectRuleData::forLongUrl('https://example.com/third'), + RedirectRuleData::forLongUrl('https://example.com/second'), + ], ], - ], $setRules->jsonSerialize()); + $setRules->jsonSerialize(), + ); } } diff --git a/test/RedirectRules/RedirectRulesClientTest.php b/test/RedirectRules/RedirectRulesClientTest.php index 0dfa17d..c342060 100644 --- a/test/RedirectRules/RedirectRulesClientTest.php +++ b/test/RedirectRules/RedirectRulesClientTest.php @@ -25,7 +25,7 @@ class RedirectRulesClientTest extends TestCase { private RedirectRulesClient $client; - private MockObject & HttpClientInterface $httpClient; + private MockObject&HttpClientInterface $httpClient; public function setUp(): void { @@ -38,41 +38,45 @@ public function getShortUrlRedirectRulesCallsHttpClient(ShortUrlIdentifier $iden { [$shortCode, $query] = $identifier->toShortCodeAndQuery(); - $this->httpClient->expects($this->once())->method('getFromShlink')->with( - sprintf('/short-urls/%s/redirect-rules', $shortCode), - $query, - )->willReturn([ - 'defaultLongUrl' => 'https://example.com/default', - 'redirectRules' => [ - [ - 'longUrl' => 'https://example.com/android', - 'priority' => 1, - 'conditions' => [ - [ - 'type' => RedirectConditionType::DEVICE->value, - 'matchValue' => Device::ANDROID->value, - 'matchKey' => null, + $this->httpClient + ->expects($this->once()) + ->method('getFromShlink') + ->with( + sprintf('/short-urls/%s/redirect-rules', $shortCode), + $query, + ) + ->willReturn([ + 'defaultLongUrl' => 'https://example.com/default', + 'redirectRules' => [ + [ + 'longUrl' => 'https://example.com/android', + 'priority' => 1, + 'conditions' => [ + [ + 'type' => RedirectConditionType::DEVICE->value, + 'matchValue' => Device::ANDROID->value, + 'matchKey' => null, + ], ], ], - ], - [ - 'longUrl' => 'https://example.com/freanch-and-foo-bar-query', - 'priority' => 2, - 'conditions' => [ - [ - 'type' => RedirectConditionType::LANGUAGE->value, - 'matchValue' => 'fr', - 'matchKey' => null, - ], - [ - 'type' => RedirectConditionType::QUERY_PARAM->value, - 'matchValue' => 'bar', - 'matchKey' => 'foo', + [ + 'longUrl' => 'https://example.com/freanch-and-foo-bar-query', + 'priority' => 2, + 'conditions' => [ + [ + 'type' => RedirectConditionType::LANGUAGE->value, + 'matchValue' => 'fr', + 'matchKey' => null, + ], + [ + 'type' => RedirectConditionType::QUERY_PARAM->value, + 'matchValue' => 'bar', + 'matchKey' => 'foo', + ], ], ], ], - ], - ]); + ]); $result = $this->client->getShortUrlRedirectRules($identifier); @@ -126,15 +130,19 @@ public function setShortUrlRedirectRulesCallsHttpClient(ShortUrlIdentifier $iden [$shortCode, $query] = $identifier->toShortCodeAndQuery(); $rules = SetRedirectRules::fromScratch(); - $this->httpClient->expects($this->once())->method('callShlinkWithBody')->with( - sprintf('/short-urls/%s/redirect-rules', $shortCode), - 'POST', - $rules, - $query, - )->willReturn([ - 'defaultLongUrl' => 'https://example.com/default', - 'redirectRules' => [], - ]); + $this->httpClient + ->expects($this->once()) + ->method('callShlinkWithBody') + ->with( + sprintf('/short-urls/%s/redirect-rules', $shortCode), + 'POST', + $rules, + $query, + ) + ->willReturn([ + 'defaultLongUrl' => 'https://example.com/default', + 'redirectRules' => [], + ]); $result = $this->client->setShortUrlRedirectRules($identifier, $rules); diff --git a/test/ShlinkClientTest.php b/test/ShlinkClientTest.php index a41d04e..956918f 100644 --- a/test/ShlinkClientTest.php +++ b/test/ShlinkClientTest.php @@ -41,11 +41,11 @@ class ShlinkClientTest extends TestCase { private ShlinkClient $shlinkClient; - private MockObject & ShortUrlsClientInterface $shortUrlsClient; - private MockObject & VisitsClientInterface $visitsClient; - private MockObject & TagsClientInterface $tagsClient; - private MockObject & DomainsClientInterface $domainsClient; - private MockObject & RedirectRulesClientInterface $redirectRulesClient; + private MockObject&ShortUrlsClientInterface $shortUrlsClient; + private MockObject&VisitsClientInterface $visitsClient; + private MockObject&TagsClientInterface $tagsClient; + private MockObject&DomainsClientInterface $domainsClient; + private MockObject&RedirectRulesClientInterface $redirectRulesClient; public function setUp(): void { @@ -74,18 +74,24 @@ public function listDomainsDelegatesCallToProperClient(): void #[Test] public function configureDomainRedirectsDelegatesCallToProperClient(): void { - $this->domainsClient->expects($this->once())->method('configureDomainRedirects')->willReturn( - DomainRedirects::fromArray([]), - ); + $this->domainsClient + ->expects($this->once()) + ->method('configureDomainRedirects') + ->willReturn( + DomainRedirects::fromArray([]), + ); $this->shlinkClient->configureDomainRedirects(DomainRedirectsConfig::forDomain('foo.com')); } #[Test] public function listShortUrlsDelegatesCallToProperClient(): void { - $this->shortUrlsClient->expects($this->once())->method('listShortUrls')->willReturn( - ShortUrlsList::forTupleLoader(static fn () => [[], []]), - ); + $this->shortUrlsClient + ->expects($this->once()) + ->method('listShortUrls') + ->willReturn( + ShortUrlsList::forTupleLoader(static fn () => [[], []]), + ); $this->shlinkClient->listShortUrls(); } @@ -93,9 +99,13 @@ public function listShortUrlsDelegatesCallToProperClient(): void public function listShortUrlsWithFilterDelegatesCallToProperClient(): void { $filter = ShortUrlsFilter::create(); - $this->shortUrlsClient->expects($this->once())->method('listShortUrlsWithFilter')->with($filter)->willReturn( - ShortUrlsList::forTupleLoader(static fn () => [[], []]), - ); + $this->shortUrlsClient + ->expects($this->once()) + ->method('listShortUrlsWithFilter') + ->with($filter) + ->willReturn( + ShortUrlsList::forTupleLoader(static fn () => [[], []]), + ); $this->shlinkClient->listShortUrlsWithFilter($filter); } @@ -104,9 +114,13 @@ public function listShortUrlsWithFilterDelegatesCallToProperClient(): void public function getShortUrlDelegatesCallToProperClient(): void { $identifier = ShortUrlIdentifier::fromShortCode('foo'); - $this->shortUrlsClient->expects($this->once())->method('getShortUrl')->with($identifier)->willReturn( - ShortUrl::fromArray(['dateCreated' => (new DateTimeImmutable())->format(DateTimeInterface::ATOM)]), - ); + $this->shortUrlsClient + ->expects($this->once()) + ->method('getShortUrl') + ->with($identifier) + ->willReturn( + ShortUrl::fromArray(['dateCreated' => new DateTimeImmutable()->format(DateTimeInterface::ATOM)]), + ); $this->shlinkClient->getShortUrl($identifier); } @@ -124,9 +138,13 @@ public function deleteShortUrlDelegatesCallToProperClient(): void public function createShortUrlDelegatesCallToProperClient(): void { $data = ShortUrlCreation::forLongUrl('https://foo.com'); - $this->shortUrlsClient->expects($this->once())->method('createShortUrl')->with($data)->willReturn( - ShortUrl::fromArray(['dateCreated' => (new DateTimeImmutable())->format(DateTimeInterface::ATOM)]), - ); + $this->shortUrlsClient + ->expects($this->once()) + ->method('createShortUrl') + ->with($data) + ->willReturn( + ShortUrl::fromArray(['dateCreated' => new DateTimeImmutable()->format(DateTimeInterface::ATOM)]), + ); $this->shlinkClient->createShortUrl($data); } @@ -136,9 +154,13 @@ public function editShortUrlDelegatesCallToProperClient(): void { $identifier = ShortUrlIdentifier::fromShortCode('foo'); $data = ShortUrlEdition::create(); - $this->shortUrlsClient->expects($this->once())->method('editShortUrl')->with($identifier, $data)->willReturn( - ShortUrl::fromArray(['dateCreated' => (new DateTimeImmutable())->format(DateTimeInterface::ATOM)]), - ); + $this->shortUrlsClient + ->expects($this->once()) + ->method('editShortUrl') + ->with($identifier, $data) + ->willReturn( + ShortUrl::fromArray(['dateCreated' => new DateTimeImmutable()->format(DateTimeInterface::ATOM)]), + ); $this->shlinkClient->editShortUrl($identifier, $data); } @@ -162,9 +184,12 @@ public function listTagsWithFilterDelegatesCallToProperClient(): void #[Test] public function listTagsWithStatsDelegatesCallToProperClient(): void { - $this->tagsClient->expects($this->once())->method('listTagsWithStats')->willReturn( - TagsWithStatsList::forTupleLoader(static fn () => [[], []]), - ); + $this->tagsClient + ->expects($this->once()) + ->method('listTagsWithStats') + ->willReturn( + TagsWithStatsList::forTupleLoader(static fn () => [[], []]), + ); $this->shlinkClient->listTagsWithStats(); } @@ -172,9 +197,13 @@ public function listTagsWithStatsDelegatesCallToProperClient(): void public function listTagsWithStatsWithFilterDelegatesCallToProperClient(): void { $filter = TagsFilter::create(); - $this->tagsClient->expects($this->once())->method('listTagsWithStatsWithFilter')->with($filter)->willReturn( - TagsWithStatsList::forTupleLoader(static fn () => [[], []]), - ); + $this->tagsClient + ->expects($this->once()) + ->method('listTagsWithStatsWithFilter') + ->with($filter) + ->willReturn( + TagsWithStatsList::forTupleLoader(static fn () => [[], []]), + ); $this->shlinkClient->listTagsWithStatsWithFilter($filter); } @@ -198,9 +227,12 @@ public function deleteTagsDelegatesCallToProperClient(): void #[Test] public function getVisitsOverviewDelegatesCallToProperClient(): void { - $this->visitsClient->expects($this->once())->method('getVisitsOverview')->willReturn( - VisitsOverview::fromArray([]), - ); + $this->visitsClient + ->expects($this->once()) + ->method('getVisitsOverview') + ->willReturn( + VisitsOverview::fromArray([]), + ); $this->shlinkClient->getVisitsOverview(); } @@ -208,9 +240,13 @@ public function getVisitsOverviewDelegatesCallToProperClient(): void public function listShortUrlVisitsDelegatesCallToProperClient(): void { $identifier = ShortUrlIdentifier::fromShortCode('foo'); - $this->visitsClient->expects($this->once())->method('listShortUrlVisits')->with($identifier)->willReturn( - VisitsList::forTupleLoader(static fn () => [[], []]), - ); + $this->visitsClient + ->expects($this->once()) + ->method('listShortUrlVisits') + ->with($identifier) + ->willReturn( + VisitsList::forTupleLoader(static fn () => [[], []]), + ); $this->shlinkClient->listShortUrlVisits($identifier); } @@ -220,10 +256,14 @@ public function listShortUrlVisitsWithFilterDelegatesCallToProperClient(): void { $identifier = ShortUrlIdentifier::fromShortCode('foo'); $filter = VisitsFilter::create(); - $this->visitsClient->expects($this->once())->method('listShortUrlVisitsWithFilter')->with( - $identifier, - $filter, - )->willReturn(VisitsList::forTupleLoader(static fn () => [[], []])); + $this->visitsClient + ->expects($this->once()) + ->method('listShortUrlVisitsWithFilter') + ->with( + $identifier, + $filter, + ) + ->willReturn(VisitsList::forTupleLoader(static fn () => [[], []])); $this->shlinkClient->listShortUrlVisitsWithFilter($identifier, $filter); } @@ -231,9 +271,13 @@ public function listShortUrlVisitsWithFilterDelegatesCallToProperClient(): void #[Test] public function listTagVisitsDelegatesCallToProperClient(): void { - $this->visitsClient->expects($this->once())->method('listTagVisits')->with('foo')->willReturn( - VisitsList::forTupleLoader(static fn () => [[], []]), - ); + $this->visitsClient + ->expects($this->once()) + ->method('listTagVisits') + ->with('foo') + ->willReturn( + VisitsList::forTupleLoader(static fn () => [[], []]), + ); $this->shlinkClient->listTagVisits('foo'); } @@ -241,10 +285,14 @@ public function listTagVisitsDelegatesCallToProperClient(): void public function listTagVisitsWithFilterDelegatesCallToProperClient(): void { $filter = VisitsFilter::create(); - $this->visitsClient->expects($this->once())->method('listTagVisitsWithFilter')->with( - 'foo', - $filter, - )->willReturn(VisitsList::forTupleLoader(static fn () => [[], []])); + $this->visitsClient + ->expects($this->once()) + ->method('listTagVisitsWithFilter') + ->with( + 'foo', + $filter, + ) + ->willReturn(VisitsList::forTupleLoader(static fn () => [[], []])); $this->shlinkClient->listTagVisitsWithFilter('foo', $filter); } @@ -252,9 +300,12 @@ public function listTagVisitsWithFilterDelegatesCallToProperClient(): void #[Test] public function listDefaultDomainVisitsDelegatesCallToProperClient(): void { - $this->visitsClient->expects($this->once())->method('listDefaultDOmainVisits')->willReturn( - VisitsList::forTupleLoader(static fn () => [[], []]), - ); + $this->visitsClient + ->expects($this->once()) + ->method('listDefaultDOmainVisits') + ->willReturn( + VisitsList::forTupleLoader(static fn () => [[], []]), + ); $this->shlinkClient->listDefaultDOmainVisits(); } @@ -262,9 +313,13 @@ public function listDefaultDomainVisitsDelegatesCallToProperClient(): void public function listDefaultDomainVisitsWithFilterDelegatesCallToProperClient(): void { $filter = VisitsFilter::create(); - $this->visitsClient->expects($this->once())->method('listDefaultDOmainVisitsWithFilter')->with( - $filter, - )->willReturn(VisitsList::forTupleLoader(static fn () => [[], []])); + $this->visitsClient + ->expects($this->once()) + ->method('listDefaultDOmainVisitsWithFilter') + ->with( + $filter, + ) + ->willReturn(VisitsList::forTupleLoader(static fn () => [[], []])); $this->shlinkClient->listDefaultDOmainVisitsWithFilter($filter); } @@ -272,9 +327,13 @@ public function listDefaultDomainVisitsWithFilterDelegatesCallToProperClient(): #[Test] public function listDomainVisitsDelegatesCallToProperClient(): void { - $this->visitsClient->expects($this->once())->method('listDomainVisits')->with('foo.com')->willReturn( - VisitsList::forTupleLoader(static fn () => [[], []]), - ); + $this->visitsClient + ->expects($this->once()) + ->method('listDomainVisits') + ->with('foo.com') + ->willReturn( + VisitsList::forTupleLoader(static fn () => [[], []]), + ); $this->shlinkClient->listDomainVisits('foo.com'); } @@ -282,10 +341,14 @@ public function listDomainVisitsDelegatesCallToProperClient(): void public function listDomainVisitsWithFilterDelegatesCallToProperClient(): void { $filter = VisitsFilter::create(); - $this->visitsClient->expects($this->once())->method('listDomainVisitsWithFilter')->with( - 'foo.com', - $filter, - )->willReturn(VisitsList::forTupleLoader(static fn () => [[], []])); + $this->visitsClient + ->expects($this->once()) + ->method('listDomainVisitsWithFilter') + ->with( + 'foo.com', + $filter, + ) + ->willReturn(VisitsList::forTupleLoader(static fn () => [[], []])); $this->shlinkClient->listDomainVisitsWithFilter('foo.com', $filter); } @@ -293,9 +356,12 @@ public function listDomainVisitsWithFilterDelegatesCallToProperClient(): void #[Test] public function listOrphanVisitsDelegatesCallToProperClient(): void { - $this->visitsClient->expects($this->once())->method('listOrphanVisits')->willReturn( - VisitsList::forOrphanVisitsTupleLoader(static fn () => [[], []]), - ); + $this->visitsClient + ->expects($this->once()) + ->method('listOrphanVisits') + ->willReturn( + VisitsList::forOrphanVisitsTupleLoader(static fn () => [[], []]), + ); $this->shlinkClient->listOrphanVisits(); } @@ -313,9 +379,13 @@ public function listOrphanVisitsWithFilterDelegatesCallToProperClient(OrphanVisi OrphanVisitType::REGULAR_NOT_FOUND => OrphanVisitsFilter::create()->onlyIncludingRegularNotFound(), }; - $this->visitsClient->expects($this->once())->method('listOrphanVisitsWithFilter')->with( - $filter, - )->willReturn(VisitsList::forOrphanVisitsTupleLoader(static fn () => [[], []])); + $this->visitsClient + ->expects($this->once()) + ->method('listOrphanVisitsWithFilter') + ->with( + $filter, + ) + ->willReturn(VisitsList::forOrphanVisitsTupleLoader(static fn () => [[], []])); $this->shlinkClient->listOrphanVisitsWithFilter($filter); } @@ -323,9 +393,12 @@ public function listOrphanVisitsWithFilterDelegatesCallToProperClient(OrphanVisi #[Test] public function listNonOrphanVisitsDelegatesCallToProperClient(): void { - $this->visitsClient->expects($this->once())->method('listNonOrphanVisits')->willReturn( - VisitsList::forTupleLoader(static fn () => [[], []]), - ); + $this->visitsClient + ->expects($this->once()) + ->method('listNonOrphanVisits') + ->willReturn( + VisitsList::forTupleLoader(static fn () => [[], []]), + ); $this->shlinkClient->listNonOrphanVisits(); } @@ -333,9 +406,13 @@ public function listNonOrphanVisitsDelegatesCallToProperClient(): void public function listNonOrphanVisitsWithFilterDelegatesCallToProperClient(): void { $filter = VisitsFilter::create(); - $this->visitsClient->expects($this->once())->method('listNonOrphanVisitsWithFilter')->with($filter)->willReturn( - VisitsList::forTupleLoader(static fn () => [[], []]), - ); + $this->visitsClient + ->expects($this->once()) + ->method('listNonOrphanVisitsWithFilter') + ->with($filter) + ->willReturn( + VisitsList::forTupleLoader(static fn () => [[], []]), + ); $this->shlinkClient->listNonOrphanVisitsWithFilter($filter); } @@ -343,9 +420,12 @@ public function listNonOrphanVisitsWithFilterDelegatesCallToProperClient(): void #[Test] public function deleteOrphanVisitsDelegatesCallToProperClient(): void { - $this->visitsClient->expects($this->once())->method('deleteOrphanVisits')->willReturn( - VisitsDeletion::fromArray([]), - ); + $this->visitsClient + ->expects($this->once()) + ->method('deleteOrphanVisits') + ->willReturn( + VisitsDeletion::fromArray([]), + ); $this->shlinkClient->deleteOrphanVisits(); } @@ -353,9 +433,13 @@ public function deleteOrphanVisitsDelegatesCallToProperClient(): void public function deleteShortUrlVisitsDelegatesCallToProperClient(): void { $identifier = ShortUrlIdentifier::fromShortCode('foo'); - $this->visitsClient->expects($this->once())->method('deleteShortUrlVisits')->with($identifier)->willReturn( - VisitsDeletion::fromArray([]), - ); + $this->visitsClient + ->expects($this->once()) + ->method('deleteShortUrlVisits') + ->with($identifier) + ->willReturn( + VisitsDeletion::fromArray([]), + ); $this->shlinkClient->deleteShortUrlVisits($identifier); } @@ -363,9 +447,13 @@ public function deleteShortUrlVisitsDelegatesCallToProperClient(): void public function getShortUrlRedirectRulesDelegatesCallToProperClient(): void { $identifier = ShortUrlIdentifier::fromShortCode('foo'); - $this->redirectRulesClient->expects($this->once())->method('getShortUrlRedirectRules')->with( - $identifier, - )->willReturn(RedirectRulesList::fromArray([])); + $this->redirectRulesClient + ->expects($this->once()) + ->method('getShortUrlRedirectRules') + ->with( + $identifier, + ) + ->willReturn(RedirectRulesList::fromArray([])); $this->shlinkClient->getShortUrlRedirectRules($identifier); } @@ -374,10 +462,14 @@ public function setShortUrlRedirectRulesDelegatesCallToProperClient(): void { $identifier = ShortUrlIdentifier::fromShortCode('foo'); $rules = SetRedirectRules::fromScratch(); - $this->redirectRulesClient->expects($this->once())->method('setShortUrlRedirectRules')->with( - $identifier, - $rules, - )->willReturn(RedirectRulesList::fromArray([])); + $this->redirectRulesClient + ->expects($this->once()) + ->method('setShortUrlRedirectRules') + ->with( + $identifier, + $rules, + ) + ->willReturn(RedirectRulesList::fromArray([])); $this->shlinkClient->setShortUrlRedirectRules($identifier, $rules); } } diff --git a/test/ShortUrls/Exception/DeleteShortUrlThresholdExceptionTest.php b/test/ShortUrls/Exception/DeleteShortUrlThresholdExceptionTest.php index f2ea272..882e9eb 100644 --- a/test/ShortUrls/Exception/DeleteShortUrlThresholdExceptionTest.php +++ b/test/ShortUrls/Exception/DeleteShortUrlThresholdExceptionTest.php @@ -32,16 +32,28 @@ public function exceptionIsProperlyCreated( public static function provideExceptions(): iterable { yield [HttpException::fromPayload([]), ShortUrlIdentifier::fromShortCode(''), 0, '', -1]; - yield [HttpException::fromPayload([ - 'detail' => $message = 'This is the message', - 'status' => $code = 404, - ]), ShortUrlIdentifier::fromShortCode(''), 0, $message, $code]; - yield [HttpException::fromPayload([ - 'detail' => $message = 'This is the message', - 'status' => $code = 400, - 'shortCode' => $shortCode = 'foo', - 'domain' => $domain = 's.test', - 'threshold' => $threshold = 15, - ]), ShortUrlIdentifier::fromShortCodeAndDomain($shortCode, $domain), $threshold, $message, $code]; + yield [ + HttpException::fromPayload([ + 'detail' => $message = 'This is the message', + 'status' => $code = 404, + ]), + ShortUrlIdentifier::fromShortCode(''), + 0, + $message, + $code, + ]; + yield [ + HttpException::fromPayload([ + 'detail' => $message = 'This is the message', + 'status' => $code = 400, + 'shortCode' => $shortCode = 'foo', + 'domain' => $domain = 's.test', + 'threshold' => $threshold = 15, + ]), + ShortUrlIdentifier::fromShortCodeAndDomain($shortCode, $domain), + $threshold, + $message, + $code, + ]; } } diff --git a/test/ShortUrls/Exception/InvalidLongUrlExceptionTest.php b/test/ShortUrls/Exception/InvalidLongUrlExceptionTest.php index 3dcc9cb..7dcea70 100644 --- a/test/ShortUrls/Exception/InvalidLongUrlExceptionTest.php +++ b/test/ShortUrls/Exception/InvalidLongUrlExceptionTest.php @@ -29,14 +29,24 @@ public function exceptionIsProperlyCreated( public static function provideExceptions(): iterable { yield [HttpException::fromPayload([]), '', '', -1]; - yield [HttpException::fromPayload([ - 'detail' => $message = 'This is the message', - 'status' => $code = 400, - ]), '', $message, $code]; - yield [HttpException::fromPayload([ - 'detail' => $message = 'This is the message', - 'status' => $code = 404, - 'url' => $url = 'https://foo.com/baz', - ]), $url, $message, $code]; + yield [ + HttpException::fromPayload([ + 'detail' => $message = 'This is the message', + 'status' => $code = 400, + ]), + '', + $message, + $code, + ]; + yield [ + HttpException::fromPayload([ + 'detail' => $message = 'This is the message', + 'status' => $code = 404, + 'url' => $url = 'https://foo.com/baz', + ]), + $url, + $message, + $code, + ]; } } diff --git a/test/ShortUrls/Exception/NonUniqueSlugExceptionTest.php b/test/ShortUrls/Exception/NonUniqueSlugExceptionTest.php index cc5e50e..ed81c4b 100644 --- a/test/ShortUrls/Exception/NonUniqueSlugExceptionTest.php +++ b/test/ShortUrls/Exception/NonUniqueSlugExceptionTest.php @@ -31,15 +31,27 @@ public function exceptionIsProperlyCreated( public static function provideExceptions(): iterable { yield [HttpException::fromPayload([]), '', null, '', -1]; - yield [HttpException::fromPayload([ - 'detail' => $message = 'This is the message', - 'status' => $code = 400, - ]), '', null, $message, $code]; - yield [HttpException::fromPayload([ - 'detail' => $message = 'This is the message', - 'status' => $code = 404, - 'customSlug' => $customSlug = 'baz', - 'domain' => $domain = 's.test', - ]), $customSlug, $domain, $message, $code]; + yield [ + HttpException::fromPayload([ + 'detail' => $message = 'This is the message', + 'status' => $code = 400, + ]), + '', + null, + $message, + $code, + ]; + yield [ + HttpException::fromPayload([ + 'detail' => $message = 'This is the message', + 'status' => $code = 404, + 'customSlug' => $customSlug = 'baz', + 'domain' => $domain = 's.test', + ]), + $customSlug, + $domain, + $message, + $code, + ]; } } diff --git a/test/ShortUrls/Exception/ShortUrlNotFoundExceptionTest.php b/test/ShortUrls/Exception/ShortUrlNotFoundExceptionTest.php index 6bcbcb1..693f367 100644 --- a/test/ShortUrls/Exception/ShortUrlNotFoundExceptionTest.php +++ b/test/ShortUrls/Exception/ShortUrlNotFoundExceptionTest.php @@ -30,20 +30,35 @@ public function exceptionIsProperlyCreated( public static function provideExceptions(): iterable { yield [HttpException::fromPayload([]), ShortUrlIdentifier::fromShortCode(''), '', -1]; - yield [HttpException::fromPayload([ - 'detail' => $message = 'This is the message', - 'status' => $code = 404, - ]), ShortUrlIdentifier::fromShortCode(''), $message, $code]; - yield [HttpException::fromPayload([ - 'detail' => $message = 'This is the message', - 'status' => $code = 400, - 'shortCode' => $shortCode = 'foo', - ]), ShortUrlIdentifier::fromShortCode($shortCode), $message, $code]; - yield [HttpException::fromPayload([ - 'detail' => $message = 'This is the message', - 'status' => $code = 400, - 'shortCode' => $shortCode = 'foo', - 'domain' => $domain = 's.test', - ]), ShortUrlIdentifier::fromShortCodeAndDomain($shortCode, $domain), $message, $code]; + yield [ + HttpException::fromPayload([ + 'detail' => $message = 'This is the message', + 'status' => $code = 404, + ]), + ShortUrlIdentifier::fromShortCode(''), + $message, + $code, + ]; + yield [ + HttpException::fromPayload([ + 'detail' => $message = 'This is the message', + 'status' => $code = 400, + 'shortCode' => $shortCode = 'foo', + ]), + ShortUrlIdentifier::fromShortCode($shortCode), + $message, + $code, + ]; + yield [ + HttpException::fromPayload([ + 'detail' => $message = 'This is the message', + 'status' => $code = 400, + 'shortCode' => $shortCode = 'foo', + 'domain' => $domain = 's.test', + ]), + ShortUrlIdentifier::fromShortCodeAndDomain($shortCode, $domain), + $message, + $code, + ]; } } diff --git a/test/ShortUrls/Model/ShortUrlCreationTest.php b/test/ShortUrls/Model/ShortUrlCreationTest.php index 21d4e3d..fae20c5 100644 --- a/test/ShortUrls/Model/ShortUrlCreationTest.php +++ b/test/ShortUrls/Model/ShortUrlCreationTest.php @@ -26,13 +26,13 @@ public static function provideConfigs(): iterable { $date = DateTimeImmutable::createFromFormat('Y-m-d', '2021-01-01'); - yield [fn () => ShortUrlCreation::forLongUrl('https://foo.com'), ['longUrl' => 'https://foo.com']]; + yield [static fn () => ShortUrlCreation::forLongUrl('https://foo.com'), ['longUrl' => 'https://foo.com']]; yield [ - fn () => ShortUrlCreation::forLongUrl('https://foo.com')->returnExistingMatchingShortUrl(), + static fn () => ShortUrlCreation::forLongUrl('https://foo.com')->returnExistingMatchingShortUrl(), ['longUrl' => 'https://foo.com', 'findIfExists' => true], ]; yield [ - fn () => ShortUrlCreation::forLongUrl('https://foo.com') + static fn () => ShortUrlCreation::forLongUrl('https://foo.com') ->withTags('foo', 'bar') ->validSince($date) // @phpstan-ignore-line ->withCustomSlug('some-slug') @@ -46,25 +46,25 @@ public static function provideConfigs(): iterable ], ]; yield [ - fn () => ShortUrlCreation::forLongUrl('https://foo.com') + static fn () => ShortUrlCreation::forLongUrl('https://foo.com') ->withCustomSlug('some-slug') ->withPathPrefix('my-prefix-') ->withShortCodeLength(50), ['longUrl' => 'https://foo.com', 'pathPrefix' => 'my-prefix-', 'shortCodeLength' => 50], ]; yield [ - fn () => ShortUrlCreation::forLongUrl('https://foo.com') + static fn () => ShortUrlCreation::forLongUrl('https://foo.com') ->withShortCodeLength(50) ->withCustomSlug('some-slug') ->withPathPrefix('my-prefix-'), ['longUrl' => 'https://foo.com', 'customSlug' => 'some-slug', 'pathPrefix' => 'my-prefix-'], ]; yield [ - fn () => ShortUrlCreation::forLongUrl('https://foo.com')->crawlable(), + static fn () => ShortUrlCreation::forLongUrl('https://foo.com')->crawlable(), ['longUrl' => 'https://foo.com', 'crawlable' => true], ]; yield [ - fn () => ShortUrlCreation::forLongUrl('https://foo.com') + static fn () => ShortUrlCreation::forLongUrl('https://foo.com') ->withoutQueryForwardingOnRedirect() ->forDomain('s.test'), ['longUrl' => 'https://foo.com', 'forwardQuery' => false, 'domain' => 's.test'], diff --git a/test/ShortUrls/Model/ShortUrlEditionTest.php b/test/ShortUrls/Model/ShortUrlEditionTest.php index 7298716..981ffa3 100644 --- a/test/ShortUrls/Model/ShortUrlEditionTest.php +++ b/test/ShortUrls/Model/ShortUrlEditionTest.php @@ -26,9 +26,9 @@ public static function provideConfigs(): iterable { $date = DateTimeImmutable::createFromFormat('Y-m-d', '2021-01-01'); - yield [fn () => ShortUrlEdition::create(), []]; + yield [ShortUrlEdition::create(...), []]; yield [ - fn () => ShortUrlEdition::create() + static fn () => ShortUrlEdition::create() ->withTags('foo', 'bar') ->validUntil($date) // @phpstan-ignore-line ->withTitle('the title') @@ -41,13 +41,13 @@ public static function provideConfigs(): iterable ], ]; yield [ - fn () => ShortUrlEdition::create() + static fn () => ShortUrlEdition::create() ->withLongUrl('https://edited.com/foo/bar') ->withoutTags(), ['longUrl' => 'https://edited.com/foo/bar', 'tags' => []], ]; yield [ - fn () => ShortUrlEdition::create() + static fn () => ShortUrlEdition::create() ->removingValidUntil() ->removingValidSince() ->removingMaxVisits() diff --git a/test/ShortUrls/Model/ShortUrlMetaTest.php b/test/ShortUrls/Model/ShortUrlMetaTest.php index 52e3239..1bf7e1d 100644 --- a/test/ShortUrls/Model/ShortUrlMetaTest.php +++ b/test/ShortUrls/Model/ShortUrlMetaTest.php @@ -33,10 +33,15 @@ public static function providePayloads(): iterable $formattedDate = $now->format(DateTimeInterface::ATOM); // @phpstan-ignore-line yield 'defaults' => [[], null, null, null]; - yield 'all data' => [[ - 'validSince' => $formattedDate, - 'validUntil' => $formattedDate, - 'maxVisits' => 35, - ], $now, $now, 35]; + yield 'all data' => [ + [ + 'validSince' => $formattedDate, + 'validUntil' => $formattedDate, + 'maxVisits' => 35, + ], + $now, + $now, + 35, + ]; } } diff --git a/test/ShortUrls/Model/ShortUrlTest.php b/test/ShortUrls/Model/ShortUrlTest.php index 200ec57..ea01994 100644 --- a/test/ShortUrls/Model/ShortUrlTest.php +++ b/test/ShortUrls/Model/ShortUrlTest.php @@ -75,14 +75,16 @@ public static function providePayloads(): iterable 'crawlable' => true, 'forwardQuery' => true, 'tags' => ['foo', 'bar'], - 'meta' => $meta = [ - 'maxVisits' => 30, - ], - 'visitsSummary' => $visitsSummary = [ - 'total' => 3, - 'nonBots' => 3, - 'bots' => 3, - ], + 'meta' => + $meta = [ + 'maxVisits' => 30, + ], + 'visitsSummary' => + $visitsSummary = [ + 'total' => 3, + 'nonBots' => 3, + 'bots' => 3, + ], ], 'foo', 'https://s.test/foo', diff --git a/test/ShortUrls/Model/ShortUrlsFilterTest.php b/test/ShortUrls/Model/ShortUrlsFilterTest.php index 07d6c7d..9d68e7f 100644 --- a/test/ShortUrls/Model/ShortUrlsFilterTest.php +++ b/test/ShortUrls/Model/ShortUrlsFilterTest.php @@ -27,44 +27,44 @@ public static function providePayloads(): iterable { $date = new DateTimeImmutable(); - yield [fn () => ShortUrlsFilter::create(), []]; + yield [ShortUrlsFilter::create(...), []]; yield [ - fn () => ShortUrlsFilter::create() + static fn () => ShortUrlsFilter::create() ->since($date) ->until($date), ['startDate' => $formatted = $date->format(DateTimeInterface::ATOM), 'endDate' => $formatted], ]; yield [ - fn () => ShortUrlsFilter::create() + static fn () => ShortUrlsFilter::create() ->containingSomeTags('foo', 'bar') ->searchingBy('searching'), ['tags' => ['foo', 'bar'], 'tagsMode' => 'any', 'searchTerm' => 'searching'], ]; yield [ - fn () => ShortUrlsFilter::create()->containingAllTags('foo', 'bar'), + static fn () => ShortUrlsFilter::create()->containingAllTags('foo', 'bar'), ['tags' => ['foo', 'bar'], 'tagsMode' => 'all'], ]; yield [ - fn () => ShortUrlsFilter::create()->orderingAscBy(ShortUrlListOrderField::VISITS), + static fn () => ShortUrlsFilter::create()->orderingAscBy(ShortUrlListOrderField::VISITS), ['orderBy' => 'visits-ASC'], ]; yield [ - fn () => ShortUrlsFilter::create()->orderingDescBy(ShortUrlListOrderField::LONG_URL), + static fn () => ShortUrlsFilter::create()->orderingDescBy(ShortUrlListOrderField::LONG_URL), ['orderBy' => 'longUrl-DESC'], ]; yield [ - fn () => ShortUrlsFilter::create()->excludingMaxVisitsReached()->excludingPastValidUntil(), + static fn () => ShortUrlsFilter::create()->excludingMaxVisitsReached()->excludingPastValidUntil(), ['excludeMaxVisitsReached' => 'true', 'excludePastValidUntil' => 'true'], ]; - yield [fn () => ShortUrlsFilter::create()->forDomain('s.test'), ['domain' => 's.test']]; + yield [static fn () => ShortUrlsFilter::create()->forDomain('s.test'), ['domain' => 's.test']]; yield [ - fn () => ShortUrlsFilter::create()->notContainingSomeTags('foo', 'bar', 'baz'), + static fn () => ShortUrlsFilter::create()->notContainingSomeTags('foo', 'bar', 'baz'), ['excludeTags' => ['foo', 'bar', 'baz'], 'excludeTagsMode' => 'any'], ]; yield [ - fn () => ShortUrlsFilter::create()->notContainingAnyTags('foo', 'bar', 'baz'), + static fn () => ShortUrlsFilter::create()->notContainingAnyTags('foo', 'bar', 'baz'), ['excludeTags' => ['foo', 'bar', 'baz'], 'excludeTagsMode' => 'all'], ]; - yield [fn () => ShortUrlsFilter::create()->createdWithApiKey('foo'), ['apiKeyName' => 'foo']]; + yield [static fn () => ShortUrlsFilter::create()->createdWithApiKey('foo'), ['apiKeyName' => 'foo']]; } } diff --git a/test/ShortUrls/ShortUrlsClientTest.php b/test/ShortUrls/ShortUrlsClientTest.php index 4169971..aacc7f6 100644 --- a/test/ShortUrls/ShortUrlsClientTest.php +++ b/test/ShortUrls/ShortUrlsClientTest.php @@ -30,15 +30,14 @@ class ShortUrlsClientTest extends TestCase { private ShortUrlsClient $client; - private MockObject & HttpClientInterface $httpClient; + private MockObject&HttpClientInterface $httpClient; private string $now; public function setUp(): void { $this->httpClient = $this->createMock(HttpClientInterface::class); $this->client = new ShortUrlsClient($this->httpClient); - $this->now = (new DateTimeImmutable())->format(DateTimeInterface::ATOM); - ; + $this->now = new DateTimeImmutable()->format(DateTimeInterface::ATOM); } #[Test] @@ -47,37 +46,41 @@ public function listShortUrlVisitsPerformsExpectedCall(): void $amountOfPages = 3; $now = $this->now; - $this->httpClient->expects($this->exactly($amountOfPages))->method('getFromShlink')->with( - '/short-urls', - $this->anything(), - )->willReturnCallback( - function ($_, array $query) use ($amountOfPages, $now) { - $page = $query['page']; - $data = [ - [ - 'shortCode' => 'shortCode_' . $page . '_1', - 'longUrl' => 'longUrl_' . $page . '_1', - 'dateCreated' => $now, - ], - [ - 'shortCode' => 'shortCode_' . $page . '_2', - 'longUrl' => 'longUrl_' . $page . '_2', - 'dateCreated' => $now, - ], - ]; - - return [ - 'shortUrls' => [ - 'data' => $data, - 'pagination' => [ - 'currentPage' => $page, - 'pagesCount' => $amountOfPages, - 'totalItems' => $amountOfPages * count($data), + $this->httpClient + ->expects($this->exactly($amountOfPages)) + ->method('getFromShlink') + ->with( + '/short-urls', + $this->anything(), + ) + ->willReturnCallback( + static function ($_, array $query) use ($amountOfPages, $now) { + $page = $query['page']; + $data = [ + [ + 'shortCode' => 'shortCode_' . $page . '_1', + 'longUrl' => 'longUrl_' . $page . '_1', + 'dateCreated' => $now, ], - ], - ]; - }, - ); + [ + 'shortCode' => 'shortCode_' . $page . '_2', + 'longUrl' => 'longUrl_' . $page . '_2', + 'dateCreated' => $now, + ], + ]; + + return [ + 'shortUrls' => [ + 'data' => $data, + 'pagination' => [ + 'currentPage' => $page, + 'pagesCount' => $amountOfPages, + 'totalItems' => $amountOfPages * count($data), + ], + ], + ]; + }, + ); $result = $this->client->listShortUrls(); @@ -88,8 +91,8 @@ function ($_, array $query) use ($amountOfPages, $now) { $count++; self::assertStringStartsWith('shortCode_', $shortUrl->shortCode); self::assertStringStartsWith('longUrl_', $shortUrl->longUrl); - self::assertStringEndsWith($index % 2 === 0 ? '_1' : '_2', $shortUrl->shortCode); - self::assertStringEndsWith($index % 2 === 0 ? '_1' : '_2', $shortUrl->longUrl); + self::assertStringEndsWith(($index % 2) === 0 ? '_1' : '_2', $shortUrl->shortCode); + self::assertStringEndsWith(($index % 2) === 0 ? '_1' : '_2', $shortUrl->longUrl); self::assertStringStartsWith($shortUrl->dateCreated->format('Y-m-d'), $now); } @@ -100,10 +103,14 @@ function ($_, array $query) use ($amountOfPages, $now) { public function getShortUrlPerformsExpectedCall(ShortUrlIdentifier $identifier): void { $expected = ['dateCreated' => $this->now]; - $this->httpClient->expects($this->once())->method('getFromShlink')->with( - sprintf('/short-urls/%s', $identifier->shortCode), - $this->callback(fn (array $query): bool => ($query['domain'] ?? null) === $identifier->domain), - )->willReturn($expected); + $this->httpClient + ->expects($this->once()) + ->method('getFromShlink') + ->with( + sprintf('/short-urls/%s', $identifier->shortCode), + $this->callback(static fn (array $query): bool => ($query['domain'] ?? null) === $identifier->domain), + ) + ->willReturn($expected); $result = $this->client->getShortUrl($identifier); @@ -113,12 +120,15 @@ public function getShortUrlPerformsExpectedCall(ShortUrlIdentifier $identifier): #[Test, DataProvider('provideIdentifiers')] public function deleteShortUrlPerformsExpectedCall(ShortUrlIdentifier $identifier): void { - $this->httpClient->expects($this->once())->method('callShlinkWithBody')->with( - sprintf('/short-urls/%s', $identifier->shortCode), - 'DELETE', - [], - $this->callback(fn (array $query): bool => ($query['domain'] ?? null) === $identifier->domain), - ); + $this->httpClient + ->expects($this->once()) + ->method('callShlinkWithBody') + ->with( + sprintf('/short-urls/%s', $identifier->shortCode), + 'DELETE', + [], + $this->callback(static fn (array $query): bool => ($query['domain'] ?? null) === $identifier->domain), + ); $this->client->deleteShortUrl($identifier); } @@ -128,12 +138,16 @@ public function editShortUrlPerformsExpectedCall(ShortUrlIdentifier $identifier) { $expected = ['dateCreated' => $this->now]; $edit = ShortUrlEdition::create(); - $this->httpClient->expects($this->once())->method('callShlinkWithBody')->with( - sprintf('/short-urls/%s', $identifier->shortCode), - 'PATCH', - $edit, - $this->callback(fn (array $query): bool => ($query['domain'] ?? null) === $identifier->domain), - )->willReturn($expected); + $this->httpClient + ->expects($this->once()) + ->method('callShlinkWithBody') + ->with( + sprintf('/short-urls/%s', $identifier->shortCode), + 'PATCH', + $edit, + $this->callback(static fn (array $query): bool => ($query['domain'] ?? null) === $identifier->domain), + ) + ->willReturn($expected); $result = $this->client->editShortUrl($identifier, $edit); @@ -151,11 +165,15 @@ public function createShortUrlPerformsExpectedCall(): void { $expected = ['dateCreated' => $this->now]; $create = ShortUrlCreation::forLongUrl('https://foo.com'); - $this->httpClient->expects($this->once())->method('callShlinkWithBody')->with( - '/short-urls', - 'POST', - $create, - )->willReturn($expected); + $this->httpClient + ->expects($this->once()) + ->method('callShlinkWithBody') + ->with( + '/short-urls', + 'POST', + $create, + ) + ->willReturn($expected); $result = $this->client->createShortUrl($create); @@ -177,8 +195,8 @@ public function getShortUrlThrowsProperExceptionOnError(HttpException $original, public static function provideGetExceptions(): iterable { yield 'no type' => [HttpException::fromPayload([]), HttpException::class]; - yield 'not expected type' => [HttpException::fromPayload(['type' => 'something else']), HttpException::class]; - yield 'INVALID_SHORTCODE' => [ + yield 'not expected type' => [HttpException::fromPayload(['type' => 'something else']), HttpException::class]; + yield 'INVALID_SHORTCODE' => [ HttpException::fromPayload(['type' => ErrorType::SHORT_URL_NOT_FOUND->value]), ShortUrlNotFoundException::class, ]; @@ -199,12 +217,12 @@ public function deleteShortUrlThrowsProperExceptionOnError(HttpException $origin public static function provideDeleteExceptions(): iterable { yield 'no type' => [HttpException::fromPayload([]), HttpException::class]; - yield 'not expected type' => [HttpException::fromPayload(['type' => 'something else']), HttpException::class]; - yield 'INVALID_SHORTCODE' => [ + yield 'not expected type' => [HttpException::fromPayload(['type' => 'something else']), HttpException::class]; + yield 'INVALID_SHORTCODE' => [ HttpException::fromPayload(['type' => ErrorType::SHORT_URL_NOT_FOUND->value]), ShortUrlNotFoundException::class, ]; - yield 'INVALID_SHORT_URL_DELETION' => [ + yield 'INVALID_SHORT_URL_DELETION' => [ HttpException::fromPayload(['type' => ErrorType::INVALID_SHORT_URL_DELETION->value]), DeleteShortUrlThresholdException::class, ]; @@ -225,12 +243,12 @@ public function createShortUrlThrowsProperExceptionOnError(HttpException $origin public static function provideCreateExceptions(): iterable { yield 'no type' => [HttpException::fromPayload([]), HttpException::class]; - yield 'not expected type' => [HttpException::fromPayload(['type' => 'something else']), HttpException::class]; - yield 'INVALID_ARGUMENT' => [ + yield 'not expected type' => [HttpException::fromPayload(['type' => 'something else']), HttpException::class]; + yield 'INVALID_ARGUMENT' => [ HttpException::fromPayload(['type' => ErrorType::INVALID_DATA->value]), InvalidDataException::class, ]; - yield 'INVALID_SLUG' => [ + yield 'INVALID_SLUG' => [ HttpException::fromPayload(['type' => ErrorType::NON_UNIQUE_SLUG->value]), NonUniqueSlugException::class, ]; @@ -251,8 +269,8 @@ public function editShortUrlThrowsProperExceptionOnError(HttpException $original public static function provideEditExceptions(): iterable { yield 'no type' => [HttpException::fromPayload([]), HttpException::class]; - yield 'not expected type' => [HttpException::fromPayload(['type' => 'something else']), HttpException::class]; - yield 'INVALID_SHORTCODE' => [ + yield 'not expected type' => [HttpException::fromPayload(['type' => 'something else']), HttpException::class]; + yield 'INVALID_SHORTCODE' => [ HttpException::fromPayload(['type' => ErrorType::SHORT_URL_NOT_FOUND->value]), ShortUrlNotFoundException::class, ]; diff --git a/test/Tags/Exception/ForbiddenTagOperationExceptionTest.php b/test/Tags/Exception/ForbiddenTagOperationExceptionTest.php index d18b02c..b8f74fa 100644 --- a/test/Tags/Exception/ForbiddenTagOperationExceptionTest.php +++ b/test/Tags/Exception/ForbiddenTagOperationExceptionTest.php @@ -24,9 +24,13 @@ public function exceptionIsProperlyCreated(HttpException $prev, string $expected public static function provideExceptions(): iterable { yield [HttpException::fromPayload([]), '', -1]; - yield [HttpException::fromPayload([ - 'detail' => $message = 'This is the message', - 'status' => $code = 404, - ]), $message, $code]; + yield [ + HttpException::fromPayload([ + 'detail' => $message = 'This is the message', + 'status' => $code = 404, + ]), + $message, + $code, + ]; } } diff --git a/test/Tags/Exception/TagConflictExceptionTest.php b/test/Tags/Exception/TagConflictExceptionTest.php index f4029af..9bb0a3c 100644 --- a/test/Tags/Exception/TagConflictExceptionTest.php +++ b/test/Tags/Exception/TagConflictExceptionTest.php @@ -31,15 +31,27 @@ public function exceptionIsProperlyCreated( public static function provideExceptions(): iterable { yield [HttpException::fromPayload([]), '', '', '', -1]; - yield [HttpException::fromPayload([ - 'detail' => $message = 'This is the message', - 'status' => $code = 404, - ]), '', '', $message, $code]; - yield [HttpException::fromPayload([ - 'detail' => $message = 'This is the message', - 'status' => $code = 409, - 'oldName' => $oldName = 'old', - 'newName' => $newName = 'new', - ]), $oldName, $newName, $message, $code]; + yield [ + HttpException::fromPayload([ + 'detail' => $message = 'This is the message', + 'status' => $code = 404, + ]), + '', + '', + $message, + $code, + ]; + yield [ + HttpException::fromPayload([ + 'detail' => $message = 'This is the message', + 'status' => $code = 409, + 'oldName' => $oldName = 'old', + 'newName' => $newName = 'new', + ]), + $oldName, + $newName, + $message, + $code, + ]; } } diff --git a/test/Tags/Exception/TagNotFoundExceptionTest.php b/test/Tags/Exception/TagNotFoundExceptionTest.php index 541a7d1..a89ab6f 100644 --- a/test/Tags/Exception/TagNotFoundExceptionTest.php +++ b/test/Tags/Exception/TagNotFoundExceptionTest.php @@ -29,14 +29,24 @@ public function exceptionIsProperlyCreated( public static function provideExceptions(): iterable { yield [HttpException::fromPayload([]), '', '', -1]; - yield [HttpException::fromPayload([ - 'detail' => $message = 'This is the message', - 'status' => $code = 400, - ]), '', $message, $code]; - yield [HttpException::fromPayload([ - 'detail' => $message = 'This is the message', - 'status' => $code = 404, - 'tag' => $tag = 'foo', - ]), $tag, $message, $code]; + yield [ + HttpException::fromPayload([ + 'detail' => $message = 'This is the message', + 'status' => $code = 400, + ]), + '', + $message, + $code, + ]; + yield [ + HttpException::fromPayload([ + 'detail' => $message = 'This is the message', + 'status' => $code = 404, + 'tag' => $tag = 'foo', + ]), + $tag, + $message, + $code, + ]; } } diff --git a/test/Tags/Model/TagsFilterTest.php b/test/Tags/Model/TagsFilterTest.php index 8a14076..18c5ab3 100644 --- a/test/Tags/Model/TagsFilterTest.php +++ b/test/Tags/Model/TagsFilterTest.php @@ -24,33 +24,35 @@ public function requiresPaginationBasedOnTheOrderingFields(callable $buildFilter public static function provideOrderings(): iterable { - yield 'no order' => [fn () => TagsFilter::create(), true]; - yield 'tag ASC' => [fn () => TagsFilter::create()->orderingAscBy(TagsListOrderField::TAG), true]; - yield 'tag DESC' => [fn () => TagsFilter::create()->orderingDescBy(TagsListOrderField::TAG), true]; + yield 'no order' => [TagsFilter::create(...), true]; + yield 'tag ASC' => [static fn () => TagsFilter::create()->orderingAscBy(TagsListOrderField::TAG), true]; + yield 'tag DESC' => [static fn () => TagsFilter::create()->orderingDescBy(TagsListOrderField::TAG), true]; yield 'shortUrlsCount ASC' => [ - fn () => TagsFilter::create()->orderingAscBy(TagsListOrderField::SHORT_URLS_COUNT), + static fn () => TagsFilter::create()->orderingAscBy(TagsListOrderField::SHORT_URLS_COUNT), false, ]; yield 'shortUrlsCount DESC' => [ - fn () => TagsFilter::create()->orderingDescBy(TagsListOrderField::SHORT_URLS_COUNT), + static fn () => TagsFilter::create()->orderingDescBy(TagsListOrderField::SHORT_URLS_COUNT), false, ]; yield 'visitsCount ASC' => [ - fn () => TagsFilter::create()->orderingAscBy(TagsListOrderField::VISITS_COUNT), + static fn () => TagsFilter::create()->orderingAscBy(TagsListOrderField::VISITS_COUNT), false, ]; yield 'visitsCount DESC' => [ - fn () => TagsFilter::create()->orderingDescBy(TagsListOrderField::VISITS_COUNT), + static fn () => TagsFilter::create()->orderingDescBy(TagsListOrderField::VISITS_COUNT), false, ]; yield 'override towards paginable' => [ - fn () => TagsFilter::create()->orderingAscBy(TagsListOrderField::SHORT_URLS_COUNT) - ->orderingDescBy(TagsListOrderField::TAG), + static fn () => TagsFilter::create() + ->orderingAscBy(TagsListOrderField::SHORT_URLS_COUNT) + ->orderingDescBy(TagsListOrderField::TAG), true, ]; yield 'override towards non-paginable' => [ - fn () => TagsFilter::create()->orderingDescBy(TagsListOrderField::TAG) - ->orderingAscBy(TagsListOrderField::VISITS_COUNT), + static fn () => TagsFilter::create() + ->orderingDescBy(TagsListOrderField::TAG) + ->orderingAscBy(TagsListOrderField::VISITS_COUNT), false, ]; } diff --git a/test/Tags/TagsClientTest.php b/test/Tags/TagsClientTest.php index 35cfd15..fb86363 100644 --- a/test/Tags/TagsClientTest.php +++ b/test/Tags/TagsClientTest.php @@ -28,7 +28,7 @@ class TagsClientTest extends TestCase { private TagsClient $tagsClient; - private MockObject & HttpClientInterface $httpClient; + private MockObject&HttpClientInterface $httpClient; public function setUp(): void { @@ -63,26 +63,29 @@ public function listTagsWithStatsReturnsExpectedResponse(): void $this->assertListTags( ['/tags/stats', $this->isArray()], [[], [], [], [], []], - fn (): array => array_map(fn () => [], [...$this->tagsClient->listTagsWithStats()]), + fn (): array => array_map(static fn () => [], [...$this->tagsClient->listTagsWithStats()]), ); } #[Test] public function listTagsWithStatsReturnsExpectedVisitsCount(): void { - $this->httpClient->expects($this->once())->method('getFromShlink')->willReturn([ - 'tags' => [ - 'data' => [[ - 'tag' => 'foo', - 'shortUrlsCount' => 1, - 'visitsSummary' => [ - 'total' => 3, - 'nonBots' => 2, - 'bots' => 1, - ], - ]], - ], - ]); + $this->httpClient + ->expects($this->once()) + ->method('getFromShlink') + ->willReturn([ + 'tags' => [ + 'data' => [[ + 'tag' => 'foo', + 'shortUrlsCount' => 1, + 'visitsSummary' => [ + 'total' => 3, + 'nonBots' => 2, + 'bots' => 1, + ], + ]], + ], + ]); $list = $this->tagsClient->listTagsWithStats(); @@ -100,26 +103,33 @@ public function listTagsWithStatsWithFilterReturnsExpectedResponse(): void { $filter = TagsFilter::create()->searchingBy('foo')->orderingAscBy(TagsListOrderField::TAG); $this->assertListTags( - ['/tags/stats', $this->callback(function (array $arg) use ($filter) { - $filterArray = $filter->toArray(); - foreach ($filterArray as $key => $expectedValue) { - Assert::assertEquals($expectedValue, $arg[$key]); - } - - return true; - })], + [ + '/tags/stats', + $this->callback(static function (array $arg) use ($filter) { + $filterArray = $filter->toArray(); + foreach ($filterArray as $key => $expectedValue) { + Assert::assertEquals($expectedValue, $arg[$key]); + } + + return true; + }), + ], [[], [], [], [], []], - fn (): array => array_map(fn () => [], [...$this->tagsClient->listTagsWithStatsWithFilter($filter)]), + fn (): array => array_map(static fn () => [], [...$this->tagsClient->listTagsWithStatsWithFilter($filter)]), ); } private function assertListTags(array $expectedArgs, array $expectedData, callable $listTags): void { - $this->httpClient->expects($this->once())->method('getFromShlink')->with(...$expectedArgs)->willReturn([ - 'tags' => [ - 'data' => $expectedData, - ], - ]); + $this->httpClient + ->expects($this->once()) + ->method('getFromShlink') + ->with(...$expectedArgs) + ->willReturn([ + 'tags' => [ + 'data' => $expectedData, + ], + ]); $result = $listTags(); @@ -150,20 +160,20 @@ public function renameTagThrowsProperExceptionOnError(HttpException $original, s public static function provideRenameExceptions(): iterable { yield 'no type' => [HttpException::fromPayload([]), HttpException::class]; - yield 'not expected type' => [HttpException::fromPayload(['type' => 'something else']), HttpException::class]; - yield 'INVALID_ARGUMENT' => [ + yield 'not expected type' => [HttpException::fromPayload(['type' => 'something else']), HttpException::class]; + yield 'INVALID_ARGUMENT' => [ HttpException::fromPayload(['type' => ErrorType::INVALID_DATA->value]), InvalidDataException::class, ]; - yield 'FORBIDDEN_OPERATION' => [ + yield 'FORBIDDEN_OPERATION' => [ HttpException::fromPayload(['type' => ErrorType::FORBIDDEN_TAG_OPERATION->value]), ForbiddenTagOperationException::class, ]; - yield 'TAG_NOT_FOUND' => [ + yield 'TAG_NOT_FOUND' => [ HttpException::fromPayload(['type' => ErrorType::TAG_NOT_FOUND->value]), TagNotFoundException::class, ]; - yield 'TAG_CONFLICT' => [ + yield 'TAG_CONFLICT' => [ HttpException::fromPayload(['type' => ErrorType::TAG_CONFLICT->value]), TagConflictException::class, ]; @@ -173,12 +183,15 @@ public static function provideRenameExceptions(): iterable public function deleteTagsCallsApi(): void { $tags = ['foo', 'bar', 'baz']; - $this->httpClient->expects($this->once())->method('callShlinkWithBody')->with( - '/tags', - 'DELETE', - [], - ['tags' => $tags], - ); + $this->httpClient + ->expects($this->once()) + ->method('callShlinkWithBody') + ->with( + '/tags', + 'DELETE', + [], + ['tags' => $tags], + ); $this->tagsClient->deleteTags(...$tags); } @@ -198,8 +211,8 @@ public function deleteTagsThrowsProperExceptionOnError(HttpException $original, public static function provideDeleteExceptions(): iterable { yield 'no type' => [HttpException::fromPayload([]), HttpException::class]; - yield 'not expected type' => [HttpException::fromPayload(['type' => 'something else']), HttpException::class]; - yield 'FORBIDDEN_OPERATION' => [ + yield 'not expected type' => [HttpException::fromPayload(['type' => 'something else']), HttpException::class]; + yield 'FORBIDDEN_OPERATION' => [ HttpException::fromPayload(['type' => ErrorType::FORBIDDEN_TAG_OPERATION->value]), ForbiddenTagOperationException::class, ]; diff --git a/test/Visits/Model/OrphanVisitTest.php b/test/Visits/Model/OrphanVisitTest.php index 626e909..2ad625c 100644 --- a/test/Visits/Model/OrphanVisitTest.php +++ b/test/Visits/Model/OrphanVisitTest.php @@ -42,9 +42,18 @@ public static function providePayloads(): iterable $now = DateTimeImmutable::createFromFormat('Y-m-d', '2021-01-01'); $formattedDate = $now->format(DateTimeInterface::ATOM); // @phpstan-ignore-line - yield 'defaults' => [[ - 'date' => $formattedDate, - ], '', $now, '', false, null, '', OrphanVisitType::REGULAR_NOT_FOUND]; + yield 'defaults' => [ + [ + 'date' => $formattedDate, + ], + '', + $now, + '', + false, + null, + '', + OrphanVisitType::REGULAR_NOT_FOUND, + ]; yield 'all data' => [ [ 'referer' => 'referer', diff --git a/test/Visits/Model/VisitsFilterTest.php b/test/Visits/Model/VisitsFilterTest.php index 64daf93..623cbe0 100644 --- a/test/Visits/Model/VisitsFilterTest.php +++ b/test/Visits/Model/VisitsFilterTest.php @@ -25,11 +25,14 @@ public static function providePayloads(): iterable { $now = new DateTimeImmutable(); - yield [fn () => VisitsFilter::create(), []]; - yield [fn () => VisitsFilter::create()->since($now), ['startDate' => $now->format(DateTimeInterface::ATOM)]]; - yield [fn () => VisitsFilter::create()->excludingBots(), ['excludeBots' => 'true']]; + yield [VisitsFilter::create(...), []]; yield [ - fn () => VisitsFilter::create() + static fn () => VisitsFilter::create()->since($now), + ['startDate' => $now->format(DateTimeInterface::ATOM)], + ]; + yield [static fn () => VisitsFilter::create()->excludingBots(), ['excludeBots' => 'true']]; + yield [ + static fn () => VisitsFilter::create() ->excludingBots() ->since($now) ->until($now), diff --git a/test/Visits/VisitsClientTest.php b/test/Visits/VisitsClientTest.php index a65b81d..244a0f0 100644 --- a/test/Visits/VisitsClientTest.php +++ b/test/Visits/VisitsClientTest.php @@ -33,33 +33,37 @@ class VisitsClientTest extends TestCase { private VisitsClient $visitsClient; - private MockObject & HttpClientInterface $httpClient; + private MockObject&HttpClientInterface $httpClient; private string $now; public function setUp(): void { $this->httpClient = $this->createMock(HttpClientInterface::class); $this->visitsClient = new VisitsClient($this->httpClient); - $this->now = (new DateTimeImmutable())->format(DateTimeInterface::ATOM); + $this->now = new DateTimeImmutable()->format(DateTimeInterface::ATOM); } #[Test] public function getVisitsOverviewPerformsExpectedCall(): void { - $this->httpClient->expects($this->once())->method('getFromShlink')->with('/visits')->willReturn([ - 'visits' => [ - 'nonOrphanVisits' => [ - 'total' => 200, - 'nonBots' => 150, - 'bots' => 50, - ], - 'orphanVisits' => [ - 'total' => 38, - 'nonBots' => 30, - 'bots' => 8, + $this->httpClient + ->expects($this->once()) + ->method('getFromShlink') + ->with('/visits') + ->willReturn([ + 'visits' => [ + 'nonOrphanVisits' => [ + 'total' => 200, + 'nonBots' => 150, + 'bots' => 50, + ], + 'orphanVisits' => [ + 'total' => 38, + 'nonBots' => 30, + 'bots' => 8, + ], ], - ], - ]); + ]); $result = $this->visitsClient->getVisitsOverview(); @@ -77,13 +81,17 @@ public function listShortUrlVisitsPerformsExpectedCall(ShortUrlIdentifier $ident { $amountOfPages = 3; - $this->httpClient->expects($this->exactly($amountOfPages))->method('getFromShlink')->with( - sprintf('/short-urls/%s/visits', $identifier->shortCode), - $this->callback(function (array $query) use ($identifier) { - $domain = $identifier->domain; - return $domain === null ? ! array_key_exists('domain', $query) : $query['domain'] === $domain; - }), - )->willReturnCallback($this->buildPaginationImplementation($amountOfPages)); + $this->httpClient + ->expects($this->exactly($amountOfPages)) + ->method('getFromShlink') + ->with( + sprintf('/short-urls/%s/visits', $identifier->shortCode), + $this->callback(static function (array $query) use ($identifier) { + $domain = $identifier->domain; + return $domain === null ? !array_key_exists('domain', $query) : $query['domain'] === $domain; + }), + ) + ->willReturnCallback($this->buildPaginationImplementation($amountOfPages)); $result = $this->visitsClient->listShortUrlVisits($identifier); @@ -111,8 +119,8 @@ public function listShortUrlVisitsThrowsProperExceptionOnError(HttpException $or public static function provideShortUrlExceptions(): iterable { yield 'no type' => [HttpException::fromPayload([]), HttpException::class]; - yield 'not expected type' => [HttpException::fromPayload(['type' => 'something else']), HttpException::class]; - yield 'INVALID_SHORTCODE' => [ + yield 'not expected type' => [HttpException::fromPayload(['type' => 'something else']), HttpException::class]; + yield 'INVALID_SHORTCODE' => [ HttpException::fromPayload(['type' => ErrorType::SHORT_URL_NOT_FOUND->value]), ShortUrlNotFoundException::class, ]; @@ -122,10 +130,14 @@ public static function provideShortUrlExceptions(): iterable public function listTagVisitsPerformsExpectedCall(): void { $amountOfPages = 5; - $this->httpClient->expects($this->exactly($amountOfPages))->method('getFromShlink')->with( - '/tags/foo/visits', - $this->anything(), - )->willReturnCallback($this->buildPaginationImplementation($amountOfPages)); + $this->httpClient + ->expects($this->exactly($amountOfPages)) + ->method('getFromShlink') + ->with( + '/tags/foo/visits', + $this->anything(), + ) + ->willReturnCallback($this->buildPaginationImplementation($amountOfPages)); $result = $this->visitsClient->listTagVisits('foo'); @@ -147,8 +159,8 @@ public function listTagVisitsThrowsProperExceptionOnError(HttpException $origina public static function provideTagExceptions(): iterable { yield 'no type' => [HttpException::fromPayload([]), HttpException::class]; - yield 'not expected type' => [HttpException::fromPayload(['type' => 'something else']), HttpException::class]; - yield 'TAG_NOT_FOUND' => [ + yield 'not expected type' => [HttpException::fromPayload(['type' => 'something else']), HttpException::class]; + yield 'TAG_NOT_FOUND' => [ HttpException::fromPayload(['type' => ErrorType::TAG_NOT_FOUND->value]), TagNotFoundException::class, ]; @@ -158,10 +170,14 @@ public static function provideTagExceptions(): iterable public function listDomainVisitsPerformsExpectedCall(): void { $amountOfPages = 5; - $this->httpClient->expects($this->exactly($amountOfPages))->method('getFromShlink')->with( - '/domains/foo.com/visits', - $this->anything(), - )->willReturnCallback($this->buildPaginationImplementation($amountOfPages)); + $this->httpClient + ->expects($this->exactly($amountOfPages)) + ->method('getFromShlink') + ->with( + '/domains/foo.com/visits', + $this->anything(), + ) + ->willReturnCallback($this->buildPaginationImplementation($amountOfPages)); $result = $this->visitsClient->listDomainVisits('foo.com'); @@ -172,10 +188,14 @@ public function listDomainVisitsPerformsExpectedCall(): void public function listDefaultDomainVisitsPerformsExpectedCall(): void { $amountOfPages = 5; - $this->httpClient->expects($this->exactly($amountOfPages))->method('getFromShlink')->with( - '/domains/DEFAULT/visits', - $this->anything(), - )->willReturnCallback($this->buildPaginationImplementation($amountOfPages)); + $this->httpClient + ->expects($this->exactly($amountOfPages)) + ->method('getFromShlink') + ->with( + '/domains/DEFAULT/visits', + $this->anything(), + ) + ->willReturnCallback($this->buildPaginationImplementation($amountOfPages)); $result = $this->visitsClient->listDefaultDomainVisits(); @@ -209,8 +229,8 @@ public function listDefaultDomainVisitsThrowsProperExceptionOnError(HttpExceptio public static function provideDomainExceptions(): iterable { yield 'no type' => [HttpException::fromPayload([]), HttpException::class]; - yield 'not expected type' => [HttpException::fromPayload(['type' => 'something else']), HttpException::class]; - yield 'DOMAIN_NOT_FOUND' => [ + yield 'not expected type' => [HttpException::fromPayload(['type' => 'something else']), HttpException::class]; + yield 'DOMAIN_NOT_FOUND' => [ HttpException::fromPayload(['type' => ErrorType::DOMAIN_NOT_FOUND->value]), DomainNotFoundException::class, ]; @@ -220,10 +240,14 @@ public static function provideDomainExceptions(): iterable public function listOrphanVisitsPerformsExpectedCall(): void { $amountOfPages = 1; - $this->httpClient->expects($this->exactly($amountOfPages))->method('getFromShlink')->with( - '/visits/orphan', - $this->anything(), - )->willReturnCallback($this->buildPaginationImplementation($amountOfPages)); + $this->httpClient + ->expects($this->exactly($amountOfPages)) + ->method('getFromShlink') + ->with( + '/visits/orphan', + $this->anything(), + ) + ->willReturnCallback($this->buildPaginationImplementation($amountOfPages)); $result = $this->visitsClient->listOrphanVisits(); @@ -246,13 +270,18 @@ public function listOrphanVisitsWithFilterPerformsExpectedCall(OrphanVisitType|n $amountOfPages = 1; $rawType = $visitsFilter->toArray()['type'] ?? null; - $this->httpClient->expects($this->exactly($amountOfPages))->method('getFromShlink')->with( - '/visits/orphan', - $this->callback( - fn (array $query) - => $rawType === null ? ! array_key_exists('type', $query) : $query['type'] === $rawType, - ), - )->willReturnCallback($this->buildPaginationImplementation($amountOfPages)); + $this->httpClient + ->expects($this->exactly($amountOfPages)) + ->method('getFromShlink') + ->with( + '/visits/orphan', + $this->callback( + static fn (array $query) => $rawType === null + ? !array_key_exists('type', $query) + : $query['type'] === $rawType, + ), + ) + ->willReturnCallback($this->buildPaginationImplementation($amountOfPages)); $result = $this->visitsClient->listOrphanVisitsWithFilter($visitsFilter); @@ -263,10 +292,14 @@ public function listOrphanVisitsWithFilterPerformsExpectedCall(OrphanVisitType|n public function listNonOrphanVisitsPerformsExpectedCall(): void { $amountOfPages = 1; - $this->httpClient->expects($this->exactly($amountOfPages))->method('getFromShlink')->with( - '/visits/non-orphan', - $this->anything(), - )->willReturnCallback($this->buildPaginationImplementation($amountOfPages)); + $this->httpClient + ->expects($this->exactly($amountOfPages)) + ->method('getFromShlink') + ->with( + '/visits/non-orphan', + $this->anything(), + ) + ->willReturnCallback($this->buildPaginationImplementation($amountOfPages)); $result = $this->visitsClient->listNonOrphanVisits(); @@ -286,8 +319,8 @@ private function assertPaginator(VisitsList $result, int $amountOfPages): void $count++; self::assertStringStartsWith('referer_', $visit->referer()); self::assertStringStartsWith('userAgent_', $visit->userAgent()); - self::assertStringEndsWith($index % 2 === 0 ? '_1' : '_2', $visit->referer()); - self::assertStringEndsWith($index % 2 === 0 ? '_1' : '_2', $visit->userAgent()); + self::assertStringEndsWith(($index % 2) === 0 ? '_1' : '_2', $visit->referer()); + self::assertStringEndsWith(($index % 2) === 0 ? '_1' : '_2', $visit->userAgent()); self::assertStringStartsWith($visit->date()->format('Y-m-d'), $this->now); } @@ -297,7 +330,7 @@ private function assertPaginator(VisitsList $result, int $amountOfPages): void private function buildPaginationImplementation(int $amountOfPages): Closure { $now = $this->now; - return function ($_, array $query) use ($amountOfPages, $now) { + return static function ($_, array $query) use ($amountOfPages, $now) { $page = $query['page']; $data = [ [ @@ -328,11 +361,15 @@ private function buildPaginationImplementation(int $amountOfPages): Closure #[Test] public function deleteOrphanVisitsPerformsExpectedCall(): void { - $this->httpClient->expects($this->once())->method('callShlinkWithBody')->with( - '/visits/orphan', - 'DELETE', - [], - )->willReturn(['deletedVisits' => 5562]); + $this->httpClient + ->expects($this->once()) + ->method('callShlinkWithBody') + ->with( + '/visits/orphan', + 'DELETE', + [], + ) + ->willReturn(['deletedVisits' => 5562]); $result = $this->visitsClient->deleteOrphanVisits(); @@ -344,11 +381,15 @@ public function deleteOrphanVisitsPerformsExpectedCall(): void public function deleteShortUrlVisitsPerformsExpectedCall(ShortUrlIdentifier $identifier): void { [$shortCode, $query] = $identifier->toShortCodeAndQuery(); - $this->httpClient->expects($this->once())->method('callShlinkWithBody')->with( - sprintf('/short-urls/%s/visits', $shortCode), - 'DELETE', - $query, - )->willReturn(['deletedVisits' => 5562]); + $this->httpClient + ->expects($this->once()) + ->method('callShlinkWithBody') + ->with( + sprintf('/short-urls/%s/visits', $shortCode), + 'DELETE', + $query, + ) + ->willReturn(['deletedVisits' => 5562]); $result = $this->visitsClient->deleteShortUrlVisits($identifier); From ef49ba153bee5c3bfc53210c4b7c2f32f5687023 Mon Sep 17 00:00:00 2001 From: Alejandro Celaya Date: Fri, 22 May 2026 18:02:18 +0200 Subject: [PATCH 2/2] Extend mago config from shlinkio/shlink-mago-config --- composer.json | 1 + mago.toml | 55 +-------------------------------------------------- 2 files changed, 2 insertions(+), 54 deletions(-) diff --git a/composer.json b/composer.json index b51ea71..94cfa0e 100644 --- a/composer.json +++ b/composer.json @@ -23,6 +23,7 @@ "phpstan/phpstan-phpunit": "^2.0", "phpunit/phpcov": "^12.0", "phpunit/phpunit": "^13.0", + "shlinkio/shlink-mago-config": "^1.0", "symfony/var-dumper": "^8.0" }, "autoload": { diff --git a/mago.toml b/mago.toml index dea99e0..84a7f29 100644 --- a/mago.toml +++ b/mago.toml @@ -3,6 +3,7 @@ # For full documentation, see https://mago.carthage.software/tools/overview version = "1" php-version = "8.4.0" +extends = "vendor/shlinkio/shlink-mago-config/mago.toml" [source] workspace = "." @@ -12,62 +13,8 @@ excludes = ["vendor"] [source.glob] literal-separator = true -[formatter] -print-width = 120 -tab-width = 4 -use-tabs = false -null-type-hint = "null_pipe_last" -space-before-arrow-function-parameter-list-parenthesis = true -break-promoted-properties-list = false -parameter-attribute-on-new-line = false -preserve-breaking-member-access-chain = true -preserve-breaking-argument-list = true -preserve-breaking-array-like = true -preserve-breaking-parameter-list = true -preserve-breaking-attribute-list = true -preserve-breaking-conditional-expression = true -preserve-breaking-condition-expression = true -preserve-redundant-logical-binary-expression-parentheses = true - -[linter] -integrations = ["phpunit"] - [linter.rules] no-literal-password = { exclude = ["test"] } no-empty-catch-clause = { exclude = ["test"] } no-empty-loop = { exclude = ["test"] } loop-does-not-iterate = { exclude = ["test"] } - -prefer-static-closure = { level = "warning" } -array-style = { level = "warning" } -prefer-early-continue = { max_allowed_statements = 2 } -no-fully-qualified-global-class-like = { enabled = true, level = "warning" } -no-fully-qualified-global-constant = { enabled = true, level = "warning" } -no-fully-qualified-global-function = { enabled = true, level = "warning" } -ambiguous-constant-access = { enabled = true, level = "warning" } -ambiguous-function-call = { enabled = true, level = "warning" } - -no-multi-assignments = { enabled = false } -no-assign-in-condition = { enabled = false } -literal-named-argument = { enabled = false } -tagged-fixme = { enabled = false } -tagged-todo = { enabled = false } -no-boolean-flag-parameter = { enabled = false } -no-else-clause = { enabled = false } -no-isset = { enabled = false } -no-empty = { enabled = false } -no-shorthand-ternary = { enabled = false } -no-ini-set = { enabled = false } -too-many-enum-cases = { enabled = false } -function-name = { enabled = false } - -# TODO Fine tune these -too-many-methods = { enabled = false } -too-many-properties = { enabled = false } -excessive-parameter-list = { enabled = false } -cyclomatic-complexity = { enabled = false } -kan-defect = { enabled = false } -halstead = { effort-threshold = 7000, enabled = false } - -# TODO Enable this -sensitive-parameter = { enabled = false }