Merge pull request #1697 from acelaya-forks/feature/phpunit-10

Feature/phpunit 10
This commit is contained in:
Alejandro Celaya 2023-02-13 19:15:33 +01:00 committed by GitHub
commit a67ccb384f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
198 changed files with 1116 additions and 1401 deletions

View File

@ -152,8 +152,8 @@ jobs:
- run: mv build/coverage-db/coverage-db.cov build/coverage-db.cov - run: mv build/coverage-db/coverage-db.cov build/coverage-db.cov
- run: mv build/coverage-api/coverage-api.cov build/coverage-api.cov - run: mv build/coverage-api/coverage-api.cov build/coverage-api.cov
- run: mv build/coverage-cli/coverage-cli.cov build/coverage-cli.cov - run: mv build/coverage-cli/coverage-cli.cov build/coverage-cli.cov
- run: wget https://phar.phpunit.de/phpcov-8.2.1.phar - run: wget https://phar.phpunit.de/phpcov-9.0.0.phar
- run: php phpcov-8.2.1.phar merge build --clover build/clover.xml - run: php phpcov-9.0.0.phar merge build --clover build/clover.xml
- name: Publish coverage - name: Publish coverage
uses: codecov/codecov-action@v1 uses: codecov/codecov-action@v1
with: with:

View File

@ -9,7 +9,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com), and this
* *Nothing* * *Nothing*
### Changed ### Changed
* *Nothing* * [#1696](https://github.com/shlinkio/shlink/issues/1696) Migrated to PHPUnit 10.
### Deprecated ### Deprecated
* *Nothing* * *Nothing*

View File

@ -20,63 +20,62 @@
"akrabat/ip-address-middleware": "^2.1", "akrabat/ip-address-middleware": "^2.1",
"cakephp/chronos": "^2.3", "cakephp/chronos": "^2.3",
"doctrine/migrations": "^3.5", "doctrine/migrations": "^3.5",
"doctrine/orm": "^2.13.3", "doctrine/orm": "^2.14",
"endroid/qr-code": "^4.6", "endroid/qr-code": "^4.7",
"geoip2/geoip2": "^2.13", "geoip2/geoip2": "^2.13",
"guzzlehttp/guzzle": "^7.5", "guzzlehttp/guzzle": "^7.5",
"happyr/doctrine-specification": "^2.0", "happyr/doctrine-specification": "^2.0",
"jaybizzle/crawler-detect": "^1.2.112", "jaybizzle/crawler-detect": "^1.2.112",
"laminas/laminas-config": "^3.7", "laminas/laminas-config": "^3.8",
"laminas/laminas-config-aggregator": "^1.11", "laminas/laminas-config-aggregator": "^1.13",
"laminas/laminas-diactoros": "^2.19", "laminas/laminas-diactoros": "^2.24",
"laminas/laminas-inputfilter": "^2.22", "laminas/laminas-inputfilter": "^2.24",
"laminas/laminas-servicemanager": "^3.19", "laminas/laminas-servicemanager": "^3.20",
"laminas/laminas-stdlib": "^3.15", "laminas/laminas-stdlib": "^3.16",
"lcobucci/jwt": "^4.2", "lcobucci/jwt": "^4.3",
"league/uri": "^6.8", "league/uri": "^6.8",
"lstrojny/functional-php": "^1.17", "lstrojny/functional-php": "^1.17",
"mezzio/mezzio": "^3.13", "mezzio/mezzio": "^3.15",
"mezzio/mezzio-fastroute": "^3.7", "mezzio/mezzio-fastroute": "^3.8",
"mezzio/mezzio-problem-details": "^1.7", "mezzio/mezzio-problem-details": "^1.11",
"mezzio/mezzio-swoole": "^4.5", "mezzio/mezzio-swoole": "^4.6",
"mlocati/ip-lib": "^1.18", "mlocati/ip-lib": "^1.18",
"mobiledetect/mobiledetectlib": "^3.74", "mobiledetect/mobiledetectlib": "^3.74",
"ocramius/proxy-manager": "^2.14", "ocramius/proxy-manager": "^2.14",
"pagerfanta/core": "^3.6", "pagerfanta/core": "^3.7",
"php-middleware/request-id": "^4.1", "php-middleware/request-id": "^4.1",
"pugx/shortid-php": "^1.1", "pugx/shortid-php": "^1.1",
"ramsey/uuid": "^4.5", "ramsey/uuid": "^4.7",
"shlinkio/shlink-common": "^5.3.1", "shlinkio/shlink-common": "^5.3.1",
"shlinkio/shlink-config": "^2.4", "shlinkio/shlink-config": "^2.4",
"shlinkio/shlink-event-dispatcher": "^2.6", "shlinkio/shlink-event-dispatcher": "^2.6",
"shlinkio/shlink-importer": "^5.0", "shlinkio/shlink-importer": "^5.0",
"shlinkio/shlink-installer": "^8.3", "shlinkio/shlink-installer": "^8.3",
"shlinkio/shlink-ip-geolocation": "^3.2", "shlinkio/shlink-ip-geolocation": "^3.2",
"spiral/roadrunner": "^2.11", "spiral/roadrunner": "^2.12",
"spiral/roadrunner-jobs": "^2.5", "spiral/roadrunner-jobs": "^2.7",
"symfony/console": "^6.1", "symfony/console": "^6.2",
"symfony/filesystem": "^6.1", "symfony/filesystem": "^6.2",
"symfony/lock": "^6.1", "symfony/lock": "^6.2",
"symfony/process": "^6.1", "symfony/process": "^6.2",
"symfony/string": "^6.1" "symfony/string": "^6.2"
}, },
"require-dev": { "require-dev": {
"cebe/php-openapi": "^1.7", "cebe/php-openapi": "^1.7",
"devster/ubench": "^2.1", "devster/ubench": "^2.1",
"dms/phpunit-arraysubset-asserts": "^0.4.0", "infection/infection": "^0.26.19",
"infection/infection": "^0.26.15",
"openswoole/ide-helper": "~4.11.5", "openswoole/ide-helper": "~4.11.5",
"phpstan/phpstan": "^1.8", "phpstan/phpstan": "^1.9",
"phpstan/phpstan-doctrine": "^1.3", "phpstan/phpstan-doctrine": "^1.3",
"phpstan/phpstan-phpunit": "^1.1", "phpstan/phpstan-phpunit": "^1.3",
"phpstan/phpstan-symfony": "^1.2", "phpstan/phpstan-symfony": "^1.2",
"phpunit/php-code-coverage": "^9.2", "phpunit/php-code-coverage": "^10.0",
"phpunit/phpunit": "^9.5", "phpunit/phpunit": "^10.0",
"roave/security-advisories": "dev-master", "roave/security-advisories": "dev-master",
"shlinkio/php-coding-standard": "~2.3.0", "shlinkio/php-coding-standard": "~2.3.0",
"shlinkio/shlink-test-utils": "^3.4", "shlinkio/shlink-test-utils": "^3.5",
"symfony/var-dumper": "^6.1", "symfony/var-dumper": "^6.2",
"veewee/composer-run-parallel": "^1.1" "veewee/composer-run-parallel": "^1.2"
}, },
"autoload": { "autoload": {
"psr-4": { "psr-4": {
@ -133,7 +132,7 @@
"test:cli": "APP_ENV=test DB_DRIVER=maria TEST_ENV=cli php vendor/bin/phpunit --order-by=random --colors=always --testdox -c phpunit-cli.xml --log-junit=build/coverage-cli/junit.xml", "test:cli": "APP_ENV=test DB_DRIVER=maria TEST_ENV=cli php vendor/bin/phpunit --order-by=random --colors=always --testdox -c phpunit-cli.xml --log-junit=build/coverage-cli/junit.xml",
"test:cli:ci": "GENERATE_COVERAGE=yes composer test:cli", "test:cli:ci": "GENERATE_COVERAGE=yes composer test:cli",
"test:cli:pretty": "GENERATE_COVERAGE=pretty composer test:cli", "test:cli:pretty": "GENERATE_COVERAGE=pretty composer test:cli",
"infect:ci:base": "infection --threads=max --only-covered --only-covering-test-cases --skip-initial-tests", "infect:ci:base": "infection --threads=max --only-covered --skip-initial-tests",
"infect:ci:unit": "@infect:ci:base --coverage=build/coverage-unit --min-msi=80", "infect:ci:unit": "@infect:ci:base --coverage=build/coverage-unit --min-msi=80",
"infect:ci:db": "@infect:ci:base --coverage=build/coverage-db --min-msi=95 --configuration=infection-db.json5", "infect:ci:db": "@infect:ci:base --coverage=build/coverage-db --min-msi=95 --configuration=infection-db.json5",
"infect:ci:api": "@infect:ci:base --coverage=build/coverage-api --min-msi=80 --configuration=infection-api.json5", "infect:ci:api": "@infect:ci:base --coverage=build/coverage-api --min-msi=80 --configuration=infection-api.json5",

View File

@ -4,13 +4,14 @@ declare(strict_types=1);
namespace ShlinkioCliTest\Shlink\CLI\Command; namespace ShlinkioCliTest\Shlink\CLI\Command;
use PHPUnit\Framework\Attributes\Test;
use Shlinkio\Shlink\CLI\Command\Api\GenerateKeyCommand; use Shlinkio\Shlink\CLI\Command\Api\GenerateKeyCommand;
use Shlinkio\Shlink\CLI\Util\ExitCodes; use Shlinkio\Shlink\CLI\Util\ExitCodes;
use Shlinkio\Shlink\TestUtils\CliTest\CliTestCase; use Shlinkio\Shlink\TestUtils\CliTest\CliTestCase;
class GenerateApiKeyTest extends CliTestCase class GenerateApiKeyTest extends CliTestCase
{ {
/** @test */ #[Test]
public function outputIsCorrect(): void public function outputIsCorrect(): void
{ {
[$output, $exitCode] = $this->exec([GenerateKeyCommand::NAME]); [$output, $exitCode] = $this->exec([GenerateKeyCommand::NAME]);

View File

@ -5,16 +5,15 @@ declare(strict_types=1);
namespace ShlinkioCliTest\Shlink\CLI\Command; namespace ShlinkioCliTest\Shlink\CLI\Command;
use Cake\Chronos\Chronos; use Cake\Chronos\Chronos;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use Shlinkio\Shlink\CLI\Command\Api\ListKeysCommand; use Shlinkio\Shlink\CLI\Command\Api\ListKeysCommand;
use Shlinkio\Shlink\CLI\Util\ExitCodes; use Shlinkio\Shlink\CLI\Util\ExitCodes;
use Shlinkio\Shlink\TestUtils\CliTest\CliTestCase; use Shlinkio\Shlink\TestUtils\CliTest\CliTestCase;
class ListApiKeysTest extends CliTestCase class ListApiKeysTest extends CliTestCase
{ {
/** #[Test, DataProvider('provideFlags')]
* @test
* @dataProvider provideFlags
*/
public function generatesExpectedOutput(array $flags, string $expectedOutput): void public function generatesExpectedOutput(array $flags, string $expectedOutput): void
{ {
[$output, $exitCode] = $this->exec([ListKeysCommand::NAME, ...$flags]); [$output, $exitCode] = $this->exec([ListKeysCommand::NAME, ...$flags]);
@ -23,7 +22,7 @@ class ListApiKeysTest extends CliTestCase
self::assertEquals(ExitCodes::EXIT_SUCCESS, $exitCode); self::assertEquals(ExitCodes::EXIT_SUCCESS, $exitCode);
} }
public function provideFlags(): iterable public static function provideFlags(): iterable
{ {
$expiredApiKeyDate = Chronos::now()->subDay()->startOfDay()->toAtomString(); $expiredApiKeyDate = Chronos::now()->subDay()->startOfDay()->toAtomString();
$enabledOnlyOutput = <<<OUT $enabledOnlyOutput = <<<OUT

View File

@ -4,22 +4,21 @@ declare(strict_types=1);
namespace ShlinkioCliTest\Shlink\CLI\Command; namespace ShlinkioCliTest\Shlink\CLI\Command;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use Shlinkio\Shlink\CLI\Command\ShortUrl\ListShortUrlsCommand; use Shlinkio\Shlink\CLI\Command\ShortUrl\ListShortUrlsCommand;
use Shlinkio\Shlink\TestUtils\CliTest\CliTestCase; use Shlinkio\Shlink\TestUtils\CliTest\CliTestCase;
class ListShortUrlsTest extends CliTestCase class ListShortUrlsTest extends CliTestCase
{ {
/** #[Test, DataProvider('provideFlagsAndOutput')]
* @test
* @dataProvider provideFlagsAndOutput
*/
public function generatesExpectedOutput(array $flags, string $expectedOutput): void public function generatesExpectedOutput(array $flags, string $expectedOutput): void
{ {
[$output] = $this->exec([ListShortUrlsCommand::NAME, ...$flags], ['no']); [$output] = $this->exec([ListShortUrlsCommand::NAME, ...$flags], ['no']);
self::assertStringContainsString($expectedOutput, $output); self::assertStringContainsString($expectedOutput, $output);
} }
public function provideFlagsAndOutput(): iterable public static function provideFlagsAndOutput(): iterable
{ {
// phpcs:disable Generic.Files.LineLength // phpcs:disable Generic.Files.LineLength
yield 'no flags' => [[], <<<OUTPUT yield 'no flags' => [[], <<<OUTPUT

View File

@ -4,6 +4,8 @@ declare(strict_types=1);
namespace ShlinkioTest\Shlink\CLI\ApiKey; namespace ShlinkioTest\Shlink\CLI\ApiKey;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Shlinkio\Shlink\CLI\ApiKey\RoleResolver; use Shlinkio\Shlink\CLI\ApiKey\RoleResolver;
@ -27,29 +29,27 @@ class RoleResolverTest extends TestCase
$this->resolver = new RoleResolver($this->domainService, 'default.com'); $this->resolver = new RoleResolver($this->domainService, 'default.com');
} }
/** #[Test, DataProvider('provideRoles')]
* @test
* @dataProvider provideRoles
*/
public function properRolesAreResolvedBasedOnInput( public function properRolesAreResolvedBasedOnInput(
InputInterface $input, callable $createInput,
array $expectedRoles, array $expectedRoles,
int $expectedDomainCalls, int $expectedDomainCalls,
): void { ): void {
$input = $createInput($this);
$this->domainService->expects($this->exactly($expectedDomainCalls))->method('getOrCreate')->with( $this->domainService->expects($this->exactly($expectedDomainCalls))->method('getOrCreate')->with(
'example.com', 'example.com',
)->willReturn($this->domainWithId(Domain::withAuthority('example.com'))); )->willReturn(self::domainWithId(Domain::withAuthority('example.com')));
$result = $this->resolver->determineRoles($input); $result = $this->resolver->determineRoles($input);
self::assertEquals($expectedRoles, $result); self::assertEquals($expectedRoles, $result);
} }
public function provideRoles(): iterable public static function provideRoles(): iterable
{ {
$domain = $this->domainWithId(Domain::withAuthority('example.com')); $domain = self::domainWithId(Domain::withAuthority('example.com'));
$buildInput = function (array $definition): InputInterface { $buildInput = static fn (array $definition) => function (TestCase $test) use ($definition): InputInterface {
$input = $this->createStub(InputInterface::class); $input = $test->createStub(InputInterface::class);
$input->method('getOption')->willReturnMap( $input->method('getOption')->willReturnMap(
map($definition, static fn (mixed $returnValue, string $param) => [$param, $returnValue]), map($definition, static fn (mixed $returnValue, string $param) => [$param, $returnValue]),
); );
@ -98,7 +98,7 @@ class RoleResolverTest extends TestCase
]; ];
} }
/** @test */ #[Test]
public function exceptionIsThrownWhenTryingToAddDomainOnlyLinkedToDefaultDomain(): void public function exceptionIsThrownWhenTryingToAddDomainOnlyLinkedToDefaultDomain(): void
{ {
$input = $this->createStub(InputInterface::class); $input = $this->createStub(InputInterface::class);
@ -114,7 +114,7 @@ class RoleResolverTest extends TestCase
$this->resolver->determineRoles($input); $this->resolver->determineRoles($input);
} }
private function domainWithId(Domain $domain): Domain private static function domainWithId(Domain $domain): Domain
{ {
$domain->setId('1'); $domain->setId('1');
return $domain; return $domain;

View File

@ -4,6 +4,7 @@ declare(strict_types=1);
namespace ShlinkioTest\Shlink\CLI\Command\Api; namespace ShlinkioTest\Shlink\CLI\Command\Api;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Shlinkio\Shlink\CLI\Command\Api\DisableKeyCommand; use Shlinkio\Shlink\CLI\Command\Api\DisableKeyCommand;
@ -25,7 +26,7 @@ class DisableKeyCommandTest extends TestCase
$this->commandTester = $this->testerForCommand(new DisableKeyCommand($this->apiKeyService)); $this->commandTester = $this->testerForCommand(new DisableKeyCommand($this->apiKeyService));
} }
/** @test */ #[Test]
public function providedApiKeyIsDisabled(): void public function providedApiKeyIsDisabled(): void
{ {
$apiKey = 'abcd1234'; $apiKey = 'abcd1234';
@ -39,7 +40,7 @@ class DisableKeyCommandTest extends TestCase
self::assertStringContainsString('API key "abcd1234" properly disabled', $output); self::assertStringContainsString('API key "abcd1234" properly disabled', $output);
} }
/** @test */ #[Test]
public function errorIsReturnedIfServiceThrowsException(): void public function errorIsReturnedIfServiceThrowsException(): void
{ {
$apiKey = 'abcd1234'; $apiKey = 'abcd1234';

View File

@ -5,6 +5,7 @@ declare(strict_types=1);
namespace ShlinkioTest\Shlink\CLI\Command\Api; namespace ShlinkioTest\Shlink\CLI\Command\Api;
use Cake\Chronos\Chronos; use Cake\Chronos\Chronos;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Shlinkio\Shlink\CLI\ApiKey\RoleResolverInterface; use Shlinkio\Shlink\CLI\ApiKey\RoleResolverInterface;
@ -32,7 +33,7 @@ class GenerateKeyCommandTest extends TestCase
$this->commandTester = $this->testerForCommand($command); $this->commandTester = $this->testerForCommand($command);
} }
/** @test */ #[Test]
public function noExpirationDateIsDefinedIfNotProvided(): void public function noExpirationDateIsDefinedIfNotProvided(): void
{ {
$this->apiKeyService->expects($this->once())->method('create')->with( $this->apiKeyService->expects($this->once())->method('create')->with(
@ -46,7 +47,7 @@ class GenerateKeyCommandTest extends TestCase
self::assertStringContainsString('Generated API key: ', $output); self::assertStringContainsString('Generated API key: ', $output);
} }
/** @test */ #[Test]
public function expirationDateIsDefinedIfProvided(): void public function expirationDateIsDefinedIfProvided(): void
{ {
$this->apiKeyService->expects($this->once())->method('create')->with( $this->apiKeyService->expects($this->once())->method('create')->with(
@ -59,7 +60,7 @@ class GenerateKeyCommandTest extends TestCase
]); ]);
} }
/** @test */ #[Test]
public function nameIsDefinedIfProvided(): void public function nameIsDefinedIfProvided(): void
{ {
$this->apiKeyService->expects($this->once())->method('create')->with( $this->apiKeyService->expects($this->once())->method('create')->with(

View File

@ -5,6 +5,8 @@ declare(strict_types=1);
namespace ShlinkioTest\Shlink\CLI\Command\Api; namespace ShlinkioTest\Shlink\CLI\Command\Api;
use Cake\Chronos\Chronos; use Cake\Chronos\Chronos;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Shlinkio\Shlink\CLI\Command\Api\ListKeysCommand; use Shlinkio\Shlink\CLI\Command\Api\ListKeysCommand;
@ -29,10 +31,7 @@ class ListKeysCommandTest extends TestCase
$this->commandTester = $this->testerForCommand(new ListKeysCommand($this->apiKeyService)); $this->commandTester = $this->testerForCommand(new ListKeysCommand($this->apiKeyService));
} }
/** #[Test, DataProvider('provideKeysAndOutputs')]
* @test
* @dataProvider provideKeysAndOutputs
*/
public function returnsExpectedOutput(array $keys, bool $enabledOnly, string $expected): void public function returnsExpectedOutput(array $keys, bool $enabledOnly, string $expected): void
{ {
$this->apiKeyService->expects($this->once())->method('listKeys')->with($enabledOnly)->willReturn($keys); $this->apiKeyService->expects($this->once())->method('listKeys')->with($enabledOnly)->willReturn($keys);
@ -43,7 +42,7 @@ class ListKeysCommandTest extends TestCase
self::assertEquals($expected, $output); self::assertEquals($expected, $output);
} }
public function provideKeysAndOutputs(): iterable public static function provideKeysAndOutputs(): iterable
{ {
$dateInThePast = Chronos::createFromFormat('Y-m-d H:i:s', '2020-01-01 00:00:00'); $dateInThePast = Chronos::createFromFormat('Y-m-d H:i:s', '2020-01-01 00:00:00');
@ -84,14 +83,14 @@ class ListKeysCommandTest extends TestCase
yield 'with roles' => [ yield 'with roles' => [
[ [
$apiKey1 = ApiKey::create(), $apiKey1 = ApiKey::create(),
$apiKey2 = $this->apiKeyWithRoles([RoleDefinition::forAuthoredShortUrls()]), $apiKey2 = self::apiKeyWithRoles([RoleDefinition::forAuthoredShortUrls()]),
$apiKey3 = $this->apiKeyWithRoles( $apiKey3 = self::apiKeyWithRoles(
[RoleDefinition::forDomain($this->domainWithId(Domain::withAuthority('example.com')))], [RoleDefinition::forDomain(self::domainWithId(Domain::withAuthority('example.com')))],
), ),
$apiKey4 = ApiKey::create(), $apiKey4 = ApiKey::create(),
$apiKey5 = $this->apiKeyWithRoles([ $apiKey5 = self::apiKeyWithRoles([
RoleDefinition::forAuthoredShortUrls(), RoleDefinition::forAuthoredShortUrls(),
RoleDefinition::forDomain($this->domainWithId(Domain::withAuthority('example.com'))), RoleDefinition::forDomain(self::domainWithId(Domain::withAuthority('example.com'))),
]), ]),
$apiKey6 = ApiKey::create(), $apiKey6 = ApiKey::create(),
], ],
@ -141,7 +140,7 @@ class ListKeysCommandTest extends TestCase
]; ];
} }
private function apiKeyWithRoles(array $roles): ApiKey private static function apiKeyWithRoles(array $roles): ApiKey
{ {
$apiKey = ApiKey::create(); $apiKey = ApiKey::create();
foreach ($roles as $role) { foreach ($roles as $role) {
@ -151,7 +150,7 @@ class ListKeysCommandTest extends TestCase
return $apiKey; return $apiKey;
} }
private function domainWithId(Domain $domain): Domain private static function domainWithId(Domain $domain): Domain
{ {
$domain->setId('1'); $domain->setId('1');
return $domain; return $domain;

View File

@ -9,6 +9,8 @@ use Doctrine\DBAL\Driver;
use Doctrine\DBAL\Platforms\AbstractPlatform; use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Platforms\SqlitePlatform; use Doctrine\DBAL\Platforms\SqlitePlatform;
use Doctrine\DBAL\Schema\AbstractSchemaManager; use Doctrine\DBAL\Schema\AbstractSchemaManager;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Shlinkio\Shlink\CLI\Command\Db\CreateDatabaseCommand; use Shlinkio\Shlink\CLI\Command\Db\CreateDatabaseCommand;
@ -63,7 +65,7 @@ class CreateDatabaseCommandTest extends TestCase
$this->commandTester = $this->testerForCommand($command); $this->commandTester = $this->testerForCommand($command);
} }
/** @test */ #[Test]
public function successMessageIsPrintedIfDatabaseAlreadyExists(): void public function successMessageIsPrintedIfDatabaseAlreadyExists(): void
{ {
$shlinkDatabase = 'shlink_database'; $shlinkDatabase = 'shlink_database';
@ -81,7 +83,7 @@ class CreateDatabaseCommandTest extends TestCase
self::assertStringContainsString('Database already exists. Run "db:migrate" command', $output); self::assertStringContainsString('Database already exists. Run "db:migrate" command', $output);
} }
/** @test */ #[Test]
public function databaseIsCreatedIfItDoesNotExist(): void public function databaseIsCreatedIfItDoesNotExist(): void
{ {
$shlinkDatabase = 'shlink_database'; $shlinkDatabase = 'shlink_database';
@ -96,10 +98,7 @@ class CreateDatabaseCommandTest extends TestCase
$this->commandTester->execute([]); $this->commandTester->execute([]);
} }
/** #[Test, DataProvider('provideEmptyDatabase')]
* @test
* @dataProvider provideEmptyDatabase
*/
public function tablesAreCreatedIfDatabaseIsEmpty(array $tables): void public function tablesAreCreatedIfDatabaseIsEmpty(array $tables): void
{ {
$shlinkDatabase = 'shlink_database'; $shlinkDatabase = 'shlink_database';
@ -124,13 +123,13 @@ class CreateDatabaseCommandTest extends TestCase
self::assertStringContainsString('Database properly created!', $output); self::assertStringContainsString('Database properly created!', $output);
} }
public function provideEmptyDatabase(): iterable public static function provideEmptyDatabase(): iterable
{ {
yield 'no tables' => [[]]; yield 'no tables' => [[]];
yield 'migrations table' => [[MIGRATIONS_TABLE]]; yield 'migrations table' => [[MIGRATIONS_TABLE]];
} }
/** @test */ #[Test]
public function databaseCheckIsSkippedForSqlite(): void public function databaseCheckIsSkippedForSqlite(): void
{ {
$this->driver->method('getDatabasePlatform')->willReturn($this->createMock(SqlitePlatform::class)); $this->driver->method('getDatabasePlatform')->willReturn($this->createMock(SqlitePlatform::class));

View File

@ -4,6 +4,7 @@ declare(strict_types=1);
namespace ShlinkioTest\Shlink\CLI\Command\Db; namespace ShlinkioTest\Shlink\CLI\Command\Db;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Shlinkio\Shlink\CLI\Command\Db\MigrateDatabaseCommand; use Shlinkio\Shlink\CLI\Command\Db\MigrateDatabaseCommand;
@ -38,7 +39,7 @@ class MigrateDatabaseCommandTest extends TestCase
$this->commandTester = $this->testerForCommand($command); $this->commandTester = $this->testerForCommand($command);
} }
/** @test */ #[Test]
public function migrationsCommandIsRunWithProperVerbosity(): void public function migrationsCommandIsRunWithProperVerbosity(): void
{ {
$this->processHelper->expects($this->once())->method('run')->with($this->isInstanceOf(OutputInterface::class), [ $this->processHelper->expects($this->once())->method('run')->with($this->isInstanceOf(OutputInterface::class), [

View File

@ -4,6 +4,8 @@ declare(strict_types=1);
namespace ShlinkioTest\Shlink\CLI\Command\Domain; namespace ShlinkioTest\Shlink\CLI\Command\Domain;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Shlinkio\Shlink\CLI\Command\Domain\DomainRedirectsCommand; use Shlinkio\Shlink\CLI\Command\Domain\DomainRedirectsCommand;
@ -30,10 +32,7 @@ class DomainRedirectsCommandTest extends TestCase
$this->commandTester = $this->testerForCommand(new DomainRedirectsCommand($this->domainService)); $this->commandTester = $this->testerForCommand(new DomainRedirectsCommand($this->domainService));
} }
/** #[Test, DataProvider('provideDomains')]
* @test
* @dataProvider provideDomains
*/
public function onlyPlainQuestionsAreAskedForNewDomainsAndDomainsWithNoRedirects(?Domain $domain): void public function onlyPlainQuestionsAreAskedForNewDomainsAndDomainsWithNoRedirects(?Domain $domain): void
{ {
$domainAuthority = 'my-domain.com'; $domainAuthority = 'my-domain.com';
@ -60,13 +59,13 @@ class DomainRedirectsCommandTest extends TestCase
self::assertEquals(3, substr_count($output, '(Leave empty for no redirect)')); self::assertEquals(3, substr_count($output, '(Leave empty for no redirect)'));
} }
public function provideDomains(): iterable public static function provideDomains(): iterable
{ {
yield 'no domain' => [null]; yield 'no domain' => [null];
yield 'domain without redirects' => [Domain::withAuthority('')]; yield 'domain without redirects' => [Domain::withAuthority('')];
} }
/** @test */ #[Test]
public function offersNewOptionsForDomainsWithExistingRedirects(): void public function offersNewOptionsForDomainsWithExistingRedirects(): void
{ {
$domainAuthority = 'example.com'; $domainAuthority = 'example.com';
@ -95,7 +94,7 @@ class DomainRedirectsCommandTest extends TestCase
self::assertEquals(3, substr_count($output, 'Remove redirect')); self::assertEquals(3, substr_count($output, 'Remove redirect'));
} }
/** @test */ #[Test]
public function authorityIsRequestedWhenNotProvidedAndNoOtherDomainsExist(): void public function authorityIsRequestedWhenNotProvidedAndNoOtherDomainsExist(): void
{ {
$domainAuthority = 'example.com'; $domainAuthority = 'example.com';
@ -117,7 +116,7 @@ class DomainRedirectsCommandTest extends TestCase
self::assertStringContainsString('Domain authority for which you want to set specific redirects', $output); self::assertStringContainsString('Domain authority for which you want to set specific redirects', $output);
} }
/** @test */ #[Test]
public function oneOfTheExistingDomainsCanBeSelected(): void public function oneOfTheExistingDomainsCanBeSelected(): void
{ {
$domainAuthority = 'existing-two.com'; $domainAuthority = 'existing-two.com';
@ -146,7 +145,7 @@ class DomainRedirectsCommandTest extends TestCase
self::assertStringContainsString($domainAuthority, $output); self::assertStringContainsString($domainAuthority, $output);
} }
/** @test */ #[Test]
public function aNewDomainCanBeCreatedEvenIfOthersAlreadyExist(): void public function aNewDomainCanBeCreatedEvenIfOthersAlreadyExist(): void
{ {
$domainAuthority = 'new-domain.com'; $domainAuthority = 'new-domain.com';

View File

@ -5,6 +5,7 @@ declare(strict_types=1);
namespace ShlinkioTest\Shlink\CLI\Command\Domain; namespace ShlinkioTest\Shlink\CLI\Command\Domain;
use Pagerfanta\Adapter\ArrayAdapter; use Pagerfanta\Adapter\ArrayAdapter;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Shlinkio\Shlink\CLI\Command\Domain\GetDomainVisitsCommand; use Shlinkio\Shlink\CLI\Command\Domain\GetDomainVisitsCommand;
@ -37,7 +38,7 @@ class GetDomainVisitsCommandTest extends TestCase
); );
} }
/** @test */ #[Test]
public function outputIsProperlyGenerated(): void public function outputIsProperlyGenerated(): void
{ {
$shortUrl = ShortUrl::createFake(); $shortUrl = ShortUrl::createFake();

View File

@ -4,6 +4,8 @@ declare(strict_types=1);
namespace ShlinkioTest\Shlink\CLI\Command\Domain; namespace ShlinkioTest\Shlink\CLI\Command\Domain;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Shlinkio\Shlink\CLI\Command\Domain\ListDomainsCommand; use Shlinkio\Shlink\CLI\Command\Domain\ListDomainsCommand;
@ -29,10 +31,7 @@ class ListDomainsCommandTest extends TestCase
$this->commandTester = $this->testerForCommand(new ListDomainsCommand($this->domainService)); $this->commandTester = $this->testerForCommand(new ListDomainsCommand($this->domainService));
} }
/** #[Test, DataProvider('provideInputsAndOutputs')]
* @test
* @dataProvider provideInputsAndOutputs
*/
public function allDomainsAreProperlyPrinted(array $input, string $expectedOutput): void public function allDomainsAreProperlyPrinted(array $input, string $expectedOutput): void
{ {
$bazDomain = Domain::withAuthority('baz.com'); $bazDomain = Domain::withAuthority('baz.com');
@ -57,7 +56,7 @@ class ListDomainsCommandTest extends TestCase
self::assertEquals(ExitCodes::EXIT_SUCCESS, $this->commandTester->getStatusCode()); self::assertEquals(ExitCodes::EXIT_SUCCESS, $this->commandTester->getStatusCode());
} }
public function provideInputsAndOutputs(): iterable public static function provideInputsAndOutputs(): iterable
{ {
$withoutRedirectsOutput = <<<OUTPUT $withoutRedirectsOutput = <<<OUTPUT
+---------+------------+ +---------+------------+

View File

@ -5,6 +5,8 @@ declare(strict_types=1);
namespace ShlinkioTest\Shlink\CLI\Command\ShortUrl; namespace ShlinkioTest\Shlink\CLI\Command\ShortUrl;
use PHPUnit\Framework\Assert; use PHPUnit\Framework\Assert;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Shlinkio\Shlink\CLI\Command\ShortUrl\CreateShortUrlCommand; use Shlinkio\Shlink\CLI\Command\ShortUrl\CreateShortUrlCommand;
@ -45,7 +47,7 @@ class CreateShortUrlCommandTest extends TestCase
$this->commandTester = $this->testerForCommand($command); $this->commandTester = $this->testerForCommand($command);
} }
/** @test */ #[Test]
public function properShortCodeIsCreatedIfLongUrlIsCorrect(): void public function properShortCodeIsCreatedIfLongUrlIsCorrect(): void
{ {
$shortUrl = ShortUrl::createFake(); $shortUrl = ShortUrl::createFake();
@ -64,7 +66,7 @@ class CreateShortUrlCommandTest extends TestCase
self::assertStringContainsString('stringified_short_url', $output); self::assertStringContainsString('stringified_short_url', $output);
} }
/** @test */ #[Test]
public function exceptionWhileParsingLongUrlOutputsError(): void public function exceptionWhileParsingLongUrlOutputsError(): void
{ {
$url = 'http://domain.com/invalid'; $url = 'http://domain.com/invalid';
@ -80,7 +82,7 @@ class CreateShortUrlCommandTest extends TestCase
self::assertStringContainsString('Provided URL http://domain.com/invalid is invalid.', $output); self::assertStringContainsString('Provided URL http://domain.com/invalid is invalid.', $output);
} }
/** @test */ #[Test]
public function providingNonUniqueSlugOutputsError(): void public function providingNonUniqueSlugOutputsError(): void
{ {
$this->urlShortener->expects($this->once())->method('shorten')->withAnyParameters()->willThrowException( $this->urlShortener->expects($this->once())->method('shorten')->withAnyParameters()->willThrowException(
@ -95,7 +97,7 @@ class CreateShortUrlCommandTest extends TestCase
self::assertStringContainsString('Provided slug "my-slug" is already in use', $output); self::assertStringContainsString('Provided slug "my-slug" is already in use', $output);
} }
/** @test */ #[Test]
public function properlyProcessesProvidedTags(): void public function properlyProcessesProvidedTags(): void
{ {
$shortUrl = ShortUrl::createFake(); $shortUrl = ShortUrl::createFake();
@ -119,10 +121,7 @@ class CreateShortUrlCommandTest extends TestCase
self::assertStringContainsString('stringified_short_url', $output); self::assertStringContainsString('stringified_short_url', $output);
} }
/** #[Test, DataProvider('provideDomains')]
* @test
* @dataProvider provideDomains
*/
public function properlyProcessesProvidedDomain(array $input, ?string $expectedDomain): void public function properlyProcessesProvidedDomain(array $input, ?string $expectedDomain): void
{ {
$this->urlShortener->expects($this->once())->method('shorten')->with( $this->urlShortener->expects($this->once())->method('shorten')->with(
@ -139,7 +138,7 @@ class CreateShortUrlCommandTest extends TestCase
self::assertEquals(ExitCodes::EXIT_SUCCESS, $this->commandTester->getStatusCode()); self::assertEquals(ExitCodes::EXIT_SUCCESS, $this->commandTester->getStatusCode());
} }
public function provideDomains(): iterable public static function provideDomains(): iterable
{ {
yield 'no domain' => [[], null]; yield 'no domain' => [[], null];
yield 'non-default domain foo' => [['--domain' => 'foo.com'], 'foo.com']; yield 'non-default domain foo' => [['--domain' => 'foo.com'], 'foo.com'];
@ -147,10 +146,7 @@ class CreateShortUrlCommandTest extends TestCase
yield 'default domain' => [['--domain' => self::DEFAULT_DOMAIN], null]; yield 'default domain' => [['--domain' => self::DEFAULT_DOMAIN], null];
} }
/** #[Test, DataProvider('provideFlags')]
* @test
* @dataProvider provideFlags
*/
public function urlValidationHasExpectedValueBasedOnProvidedFlags(array $options, ?bool $expectedValidateUrl): void public function urlValidationHasExpectedValueBasedOnProvidedFlags(array $options, ?bool $expectedValidateUrl): void
{ {
$shortUrl = ShortUrl::createFake(); $shortUrl = ShortUrl::createFake();
@ -166,7 +162,7 @@ class CreateShortUrlCommandTest extends TestCase
$this->commandTester->execute($options); $this->commandTester->execute($options);
} }
public function provideFlags(): iterable public static function provideFlags(): iterable
{ {
yield 'no flags' => [[], null]; yield 'no flags' => [[], null];
yield 'validate-url' => [['--validate-url' => true], true]; yield 'validate-url' => [['--validate-url' => true], true];

View File

@ -4,6 +4,8 @@ declare(strict_types=1);
namespace ShlinkioTest\Shlink\CLI\Command\ShortUrl; namespace ShlinkioTest\Shlink\CLI\Command\ShortUrl;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Shlinkio\Shlink\CLI\Command\ShortUrl\DeleteShortUrlCommand; use Shlinkio\Shlink\CLI\Command\ShortUrl\DeleteShortUrlCommand;
@ -30,7 +32,7 @@ class DeleteShortUrlCommandTest extends TestCase
$this->commandTester = $this->testerForCommand(new DeleteShortUrlCommand($this->service)); $this->commandTester = $this->testerForCommand(new DeleteShortUrlCommand($this->service));
} }
/** @test */ #[Test]
public function successMessageIsPrintedIfUrlIsProperlyDeleted(): void public function successMessageIsPrintedIfUrlIsProperlyDeleted(): void
{ {
$shortCode = 'abc123'; $shortCode = 'abc123';
@ -48,7 +50,7 @@ class DeleteShortUrlCommandTest extends TestCase
); );
} }
/** @test */ #[Test]
public function invalidShortCodePrintsMessage(): void public function invalidShortCodePrintsMessage(): void
{ {
$shortCode = 'abc123'; $shortCode = 'abc123';
@ -64,10 +66,7 @@ class DeleteShortUrlCommandTest extends TestCase
self::assertStringContainsString(sprintf('No URL found with short code "%s"', $shortCode), $output); self::assertStringContainsString(sprintf('No URL found with short code "%s"', $shortCode), $output);
} }
/** #[Test, DataProvider('provideRetryDeleteAnswers')]
* @test
* @dataProvider provideRetryDeleteAnswers
*/
public function deleteIsRetriedWhenThresholdIsReachedAndQuestionIsAccepted( public function deleteIsRetriedWhenThresholdIsReachedAndQuestionIsAccepted(
array $retryAnswer, array $retryAnswer,
int $expectedDeleteCalls, int $expectedDeleteCalls,
@ -98,14 +97,14 @@ class DeleteShortUrlCommandTest extends TestCase
self::assertStringContainsString($expectedMessage, $output); self::assertStringContainsString($expectedMessage, $output);
} }
public function provideRetryDeleteAnswers(): iterable public static function provideRetryDeleteAnswers(): iterable
{ {
yield 'answering yes to retry' => [['yes'], 2, 'Short URL with short code "abc123" successfully deleted.']; yield 'answering yes to retry' => [['yes'], 2, 'Short URL with short code "abc123" successfully deleted.'];
yield 'answering no to retry' => [['no'], 1, 'Short URL was not deleted.']; yield 'answering no to retry' => [['no'], 1, 'Short URL was not deleted.'];
yield 'answering default to retry' => [[PHP_EOL], 1, 'Short URL was not deleted.']; yield 'answering default to retry' => [[PHP_EOL], 1, 'Short URL was not deleted.'];
} }
/** @test */ #[Test]
public function deleteIsNotRetriedWhenThresholdIsReachedAndQuestionIsDeclined(): void public function deleteIsNotRetriedWhenThresholdIsReachedAndQuestionIsDeclined(): void
{ {
$shortCode = 'abc123'; $shortCode = 'abc123';

View File

@ -6,6 +6,7 @@ namespace ShlinkioTest\Shlink\CLI\Command\ShortUrl;
use Cake\Chronos\Chronos; use Cake\Chronos\Chronos;
use Pagerfanta\Adapter\ArrayAdapter; use Pagerfanta\Adapter\ArrayAdapter;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Shlinkio\Shlink\CLI\Command\ShortUrl\GetShortUrlVisitsCommand; use Shlinkio\Shlink\CLI\Command\ShortUrl\GetShortUrlVisitsCommand;
@ -39,7 +40,7 @@ class GetShortUrlVisitsCommandTest extends TestCase
$this->commandTester = $this->testerForCommand($command); $this->commandTester = $this->testerForCommand($command);
} }
/** @test */ #[Test]
public function noDateFlagsTriesToListWithoutDateRange(): void public function noDateFlagsTriesToListWithoutDateRange(): void
{ {
$shortCode = 'abc123'; $shortCode = 'abc123';
@ -51,7 +52,7 @@ class GetShortUrlVisitsCommandTest extends TestCase
$this->commandTester->execute(['shortCode' => $shortCode]); $this->commandTester->execute(['shortCode' => $shortCode]);
} }
/** @test */ #[Test]
public function providingDateFlagsTheListGetsFiltered(): void public function providingDateFlagsTheListGetsFiltered(): void
{ {
$shortCode = 'abc123'; $shortCode = 'abc123';
@ -69,7 +70,7 @@ class GetShortUrlVisitsCommandTest extends TestCase
]); ]);
} }
/** @test */ #[Test]
public function providingInvalidDatesPrintsWarning(): void public function providingInvalidDatesPrintsWarning(): void
{ {
$shortCode = 'abc123'; $shortCode = 'abc123';
@ -91,7 +92,7 @@ class GetShortUrlVisitsCommandTest extends TestCase
); );
} }
/** @test */ #[Test]
public function outputIsProperlyGenerated(): void public function outputIsProperlyGenerated(): void
{ {
$visit = Visit::forValidShortUrl(ShortUrl::createFake(), new Visitor('bar', 'foo', '', ''))->locate( $visit = Visit::forValidShortUrl(ShortUrl::createFake(), new Visitor('bar', 'foo', '', ''))->locate(

View File

@ -6,6 +6,8 @@ namespace ShlinkioTest\Shlink\CLI\Command\ShortUrl;
use Cake\Chronos\Chronos; use Cake\Chronos\Chronos;
use Pagerfanta\Adapter\ArrayAdapter; use Pagerfanta\Adapter\ArrayAdapter;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Shlinkio\Shlink\CLI\Command\ShortUrl\ListShortUrlsCommand; use Shlinkio\Shlink\CLI\Command\ShortUrl\ListShortUrlsCommand;
@ -41,7 +43,7 @@ class ListShortUrlsCommandTest extends TestCase
$this->commandTester = $this->testerForCommand($command); $this->commandTester = $this->testerForCommand($command);
} }
/** @test */ #[Test]
public function loadingMorePagesCallsListMoreTimes(): void public function loadingMorePagesCallsListMoreTimes(): void
{ {
// The paginator will return more than one page // The paginator will return more than one page
@ -63,7 +65,7 @@ class ListShortUrlsCommandTest extends TestCase
self::assertStringNotContainsString('Continue with page 5?', $output); self::assertStringNotContainsString('Continue with page 5?', $output);
} }
/** @test */ #[Test]
public function havingMorePagesButAnsweringNoCallsListJustOnce(): void public function havingMorePagesButAnsweringNoCallsListJustOnce(): void
{ {
// The paginator will return more than one page // The paginator will return more than one page
@ -89,7 +91,7 @@ class ListShortUrlsCommandTest extends TestCase
self::assertStringNotContainsString('Continue with page 3?', $output); self::assertStringNotContainsString('Continue with page 3?', $output);
} }
/** @test */ #[Test]
public function passingPageWillMakeListStartOnThatPage(): void public function passingPageWillMakeListStartOnThatPage(): void
{ {
$page = 5; $page = 5;
@ -101,10 +103,7 @@ class ListShortUrlsCommandTest extends TestCase
$this->commandTester->execute(['--page' => $page]); $this->commandTester->execute(['--page' => $page]);
} }
/** #[Test, DataProvider('provideOptionalFlags')]
* @test
* @dataProvider provideOptionalFlags
*/
public function provideOptionalFlagsMakesNewColumnsToBeIncluded( public function provideOptionalFlagsMakesNewColumnsToBeIncluded(
array $input, array $input,
array $expectedContents, array $expectedContents,
@ -137,7 +136,7 @@ class ListShortUrlsCommandTest extends TestCase
} }
} }
public function provideOptionalFlags(): iterable public static function provideOptionalFlags(): iterable
{ {
$apiKey = ApiKey::fromMeta(ApiKeyMeta::withName('my api key')); $apiKey = ApiKey::fromMeta(ApiKeyMeta::withName('my api key'));
$key = $apiKey->toString(); $key = $apiKey->toString();
@ -174,10 +173,7 @@ class ListShortUrlsCommandTest extends TestCase
]; ];
} }
/** #[Test, DataProvider('provideArgs')]
* @test
* @dataProvider provideArgs
*/
public function serviceIsInvokedWithProvidedArgs( public function serviceIsInvokedWithProvidedArgs(
array $commandArgs, array $commandArgs,
?int $page, ?int $page,
@ -200,7 +196,7 @@ class ListShortUrlsCommandTest extends TestCase
$this->commandTester->execute($commandArgs); $this->commandTester->execute($commandArgs);
} }
public function provideArgs(): iterable public static function provideArgs(): iterable
{ {
yield [[], 1, null, [], TagsMode::ANY->value]; yield [[], 1, null, [], TagsMode::ANY->value];
yield [['--page' => $page = 3], $page, null, [], TagsMode::ANY->value]; yield [['--page' => $page = 3], $page, null, [], TagsMode::ANY->value];
@ -241,10 +237,7 @@ class ListShortUrlsCommandTest extends TestCase
]; ];
} }
/** #[Test, DataProvider('provideOrderBy')]
* @test
* @dataProvider provideOrderBy
*/
public function orderByIsProperlyComputed(array $commandArgs, ?string $expectedOrderBy): void public function orderByIsProperlyComputed(array $commandArgs, ?string $expectedOrderBy): void
{ {
$this->shortUrlService->expects($this->once())->method('listShortUrls')->with(ShortUrlsParams::fromRawData([ $this->shortUrlService->expects($this->once())->method('listShortUrls')->with(ShortUrlsParams::fromRawData([
@ -255,7 +248,7 @@ class ListShortUrlsCommandTest extends TestCase
$this->commandTester->execute($commandArgs); $this->commandTester->execute($commandArgs);
} }
public function provideOrderBy(): iterable public static function provideOrderBy(): iterable
{ {
yield [[], null]; yield [[], null];
yield [['--order-by' => 'visits'], 'visits']; yield [['--order-by' => 'visits'], 'visits'];
@ -264,7 +257,7 @@ class ListShortUrlsCommandTest extends TestCase
yield [['--order-by' => 'title-DESC'], 'title-DESC']; yield [['--order-by' => 'title-DESC'], 'title-DESC'];
} }
/** @test */ #[Test]
public function requestingAllElementsWillSetItemsPerPage(): void public function requestingAllElementsWillSetItemsPerPage(): void
{ {
$this->shortUrlService->expects($this->once())->method('listShortUrls')->with(ShortUrlsParams::fromRawData([ $this->shortUrlService->expects($this->once())->method('listShortUrls')->with(ShortUrlsParams::fromRawData([

View File

@ -4,6 +4,7 @@ declare(strict_types=1);
namespace ShlinkioTest\Shlink\CLI\Command\ShortUrl; namespace ShlinkioTest\Shlink\CLI\Command\ShortUrl;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Shlinkio\Shlink\CLI\Command\ShortUrl\ResolveUrlCommand; use Shlinkio\Shlink\CLI\Command\ShortUrl\ResolveUrlCommand;
@ -31,7 +32,7 @@ class ResolveUrlCommandTest extends TestCase
$this->commandTester = $this->testerForCommand(new ResolveUrlCommand($this->urlResolver)); $this->commandTester = $this->testerForCommand(new ResolveUrlCommand($this->urlResolver));
} }
/** @test */ #[Test]
public function correctShortCodeResolvesUrl(): void public function correctShortCodeResolvesUrl(): void
{ {
$shortCode = 'abc123'; $shortCode = 'abc123';
@ -46,7 +47,7 @@ class ResolveUrlCommandTest extends TestCase
self::assertEquals('Long URL: ' . $expectedUrl . PHP_EOL, $output); self::assertEquals('Long URL: ' . $expectedUrl . PHP_EOL, $output);
} }
/** @test */ #[Test]
public function incorrectShortCodeOutputsErrorMessage(): void public function incorrectShortCodeOutputsErrorMessage(): void
{ {
$identifier = ShortUrlIdentifier::fromShortCodeAndDomain('abc123'); $identifier = ShortUrlIdentifier::fromShortCodeAndDomain('abc123');

View File

@ -4,6 +4,7 @@ declare(strict_types=1);
namespace ShlinkioTest\Shlink\CLI\Command\Tag; namespace ShlinkioTest\Shlink\CLI\Command\Tag;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Shlinkio\Shlink\CLI\Command\Tag\DeleteTagsCommand; use Shlinkio\Shlink\CLI\Command\Tag\DeleteTagsCommand;
@ -24,7 +25,7 @@ class DeleteTagsCommandTest extends TestCase
$this->commandTester = $this->testerForCommand(new DeleteTagsCommand($this->tagService)); $this->commandTester = $this->testerForCommand(new DeleteTagsCommand($this->tagService));
} }
/** @test */ #[Test]
public function errorIsReturnedWhenNoTagsAreProvided(): void public function errorIsReturnedWhenNoTagsAreProvided(): void
{ {
$this->commandTester->execute([]); $this->commandTester->execute([]);
@ -33,7 +34,7 @@ class DeleteTagsCommandTest extends TestCase
self::assertStringContainsString('You have to provide at least one tag name', $output); self::assertStringContainsString('You have to provide at least one tag name', $output);
} }
/** @test */ #[Test]
public function serviceIsInvokedOnSuccess(): void public function serviceIsInvokedOnSuccess(): void
{ {
$tagNames = ['foo', 'bar']; $tagNames = ['foo', 'bar'];

View File

@ -5,6 +5,7 @@ declare(strict_types=1);
namespace ShlinkioTest\Shlink\CLI\Command\Tag; namespace ShlinkioTest\Shlink\CLI\Command\Tag;
use Pagerfanta\Adapter\ArrayAdapter; use Pagerfanta\Adapter\ArrayAdapter;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Shlinkio\Shlink\CLI\Command\Tag\GetTagVisitsCommand; use Shlinkio\Shlink\CLI\Command\Tag\GetTagVisitsCommand;
@ -37,7 +38,7 @@ class GetTagVisitsCommandTest extends TestCase
); );
} }
/** @test */ #[Test]
public function outputIsProperlyGenerated(): void public function outputIsProperlyGenerated(): void
{ {
$shortUrl = ShortUrl::createFake(); $shortUrl = ShortUrl::createFake();

View File

@ -5,6 +5,7 @@ declare(strict_types=1);
namespace ShlinkioTest\Shlink\CLI\Command\Tag; namespace ShlinkioTest\Shlink\CLI\Command\Tag;
use Pagerfanta\Adapter\ArrayAdapter; use Pagerfanta\Adapter\ArrayAdapter;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Shlinkio\Shlink\CLI\Command\Tag\ListTagsCommand; use Shlinkio\Shlink\CLI\Command\Tag\ListTagsCommand;
@ -27,7 +28,7 @@ class ListTagsCommandTest extends TestCase
$this->commandTester = $this->testerForCommand(new ListTagsCommand($this->tagService)); $this->commandTester = $this->testerForCommand(new ListTagsCommand($this->tagService));
} }
/** @test */ #[Test]
public function noTagsPrintsEmptyMessage(): void public function noTagsPrintsEmptyMessage(): void
{ {
$this->tagService->expects($this->once())->method('tagsInfo')->withAnyParameters()->willReturn( $this->tagService->expects($this->once())->method('tagsInfo')->withAnyParameters()->willReturn(
@ -40,7 +41,7 @@ class ListTagsCommandTest extends TestCase
self::assertStringContainsString('No tags found', $output); self::assertStringContainsString('No tags found', $output);
} }
/** @test */ #[Test]
public function listOfTagsIsPrinted(): void public function listOfTagsIsPrinted(): void
{ {
$this->tagService->expects($this->once())->method('tagsInfo')->withAnyParameters()->willReturn( $this->tagService->expects($this->once())->method('tagsInfo')->withAnyParameters()->willReturn(

View File

@ -4,6 +4,7 @@ declare(strict_types=1);
namespace ShlinkioTest\Shlink\CLI\Command\Tag; namespace ShlinkioTest\Shlink\CLI\Command\Tag;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Shlinkio\Shlink\CLI\Command\Tag\RenameTagCommand; use Shlinkio\Shlink\CLI\Command\Tag\RenameTagCommand;
@ -27,7 +28,7 @@ class RenameTagCommandTest extends TestCase
$this->commandTester = $this->testerForCommand(new RenameTagCommand($this->tagService)); $this->commandTester = $this->testerForCommand(new RenameTagCommand($this->tagService));
} }
/** @test */ #[Test]
public function errorIsPrintedIfExceptionIsThrown(): void public function errorIsPrintedIfExceptionIsThrown(): void
{ {
$oldName = 'foo'; $oldName = 'foo';
@ -45,7 +46,7 @@ class RenameTagCommandTest extends TestCase
self::assertStringContainsString('Tag with name "foo" could not be found', $output); self::assertStringContainsString('Tag with name "foo" could not be found', $output);
} }
/** @test */ #[Test]
public function successIsPrintedIfNoErrorOccurs(): void public function successIsPrintedIfNoErrorOccurs(): void
{ {
$oldName = 'foo'; $oldName = 'foo';

View File

@ -4,6 +4,8 @@ declare(strict_types=1);
namespace ShlinkioTest\Shlink\CLI\Command\Visit; namespace ShlinkioTest\Shlink\CLI\Command\Visit;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Shlinkio\Shlink\CLI\Command\Visit\DownloadGeoLiteDbCommand; use Shlinkio\Shlink\CLI\Command\Visit\DownloadGeoLiteDbCommand;
@ -29,10 +31,7 @@ class DownloadGeoLiteDbCommandTest extends TestCase
$this->commandTester = $this->testerForCommand(new DownloadGeoLiteDbCommand($this->dbUpdater)); $this->commandTester = $this->testerForCommand(new DownloadGeoLiteDbCommand($this->dbUpdater));
} }
/** #[Test, DataProvider('provideFailureParams')]
* @test
* @dataProvider provideFailureParams
*/
public function showsProperMessageWhenGeoLiteUpdateFails( public function showsProperMessageWhenGeoLiteUpdateFails(
bool $olderDbExists, bool $olderDbExists,
string $expectedMessage, string $expectedMessage,
@ -61,7 +60,7 @@ class DownloadGeoLiteDbCommandTest extends TestCase
self::assertSame($expectedExitCode, $exitCode); self::assertSame($expectedExitCode, $exitCode);
} }
public function provideFailureParams(): iterable public static function provideFailureParams(): iterable
{ {
yield 'existing db' => [ yield 'existing db' => [
true, true,
@ -75,10 +74,7 @@ class DownloadGeoLiteDbCommandTest extends TestCase
]; ];
} }
/** #[Test, DataProvider('provideSuccessParams')]
* @test
* @dataProvider provideSuccessParams
*/
public function printsExpectedMessageWhenNoErrorOccurs(callable $checkUpdateBehavior, string $expectedMessage): void public function printsExpectedMessageWhenNoErrorOccurs(callable $checkUpdateBehavior, string $expectedMessage): void
{ {
$this->dbUpdater->expects($this->once())->method('checkDbUpdate')->withAnyParameters()->willReturnCallback( $this->dbUpdater->expects($this->once())->method('checkDbUpdate')->withAnyParameters()->willReturnCallback(
@ -93,7 +89,7 @@ class DownloadGeoLiteDbCommandTest extends TestCase
self::assertSame(ExitCodes::EXIT_SUCCESS, $exitCode); self::assertSame(ExitCodes::EXIT_SUCCESS, $exitCode);
} }
public function provideSuccessParams(): iterable public static function provideSuccessParams(): iterable
{ {
yield 'up to date db' => [fn () => GeolocationResult::CHECK_SKIPPED, '[INFO] GeoLite2 db file is up to date.']; yield 'up to date db' => [fn () => GeolocationResult::CHECK_SKIPPED, '[INFO] GeoLite2 db file is up to date.'];
yield 'outdated db' => [function (callable $beforeDownload): GeolocationResult { yield 'outdated db' => [function (callable $beforeDownload): GeolocationResult {

View File

@ -5,6 +5,7 @@ declare(strict_types=1);
namespace ShlinkioTest\Shlink\CLI\Command\Visit; namespace ShlinkioTest\Shlink\CLI\Command\Visit;
use Pagerfanta\Adapter\ArrayAdapter; use Pagerfanta\Adapter\ArrayAdapter;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Shlinkio\Shlink\CLI\Command\Visit\GetNonOrphanVisitsCommand; use Shlinkio\Shlink\CLI\Command\Visit\GetNonOrphanVisitsCommand;
@ -37,7 +38,7 @@ class GetNonOrphanVisitsCommandTest extends TestCase
); );
} }
/** @test */ #[Test]
public function outputIsProperlyGenerated(): void public function outputIsProperlyGenerated(): void
{ {
$shortUrl = ShortUrl::createFake(); $shortUrl = ShortUrl::createFake();

View File

@ -5,6 +5,7 @@ declare(strict_types=1);
namespace ShlinkioTest\Shlink\CLI\Command\Visit; namespace ShlinkioTest\Shlink\CLI\Command\Visit;
use Pagerfanta\Adapter\ArrayAdapter; use Pagerfanta\Adapter\ArrayAdapter;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Shlinkio\Shlink\CLI\Command\Visit\GetOrphanVisitsCommand; use Shlinkio\Shlink\CLI\Command\Visit\GetOrphanVisitsCommand;
@ -30,7 +31,7 @@ class GetOrphanVisitsCommandTest extends TestCase
$this->commandTester = $this->testerForCommand(new GetOrphanVisitsCommand($this->visitsHelper)); $this->commandTester = $this->testerForCommand(new GetOrphanVisitsCommand($this->visitsHelper));
} }
/** @test */ #[Test]
public function outputIsProperlyGenerated(): void public function outputIsProperlyGenerated(): void
{ {
$visit = Visit::forBasePath(new Visitor('bar', 'foo', '', ''))->locate( $visit = Visit::forBasePath(new Visitor('bar', 'foo', '', ''))->locate(

View File

@ -4,6 +4,8 @@ declare(strict_types=1);
namespace ShlinkioTest\Shlink\CLI\Command\Visit; namespace ShlinkioTest\Shlink\CLI\Command\Visit;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Shlinkio\Shlink\CLI\Command\Visit\DownloadGeoLiteDbCommand; use Shlinkio\Shlink\CLI\Command\Visit\DownloadGeoLiteDbCommand;
@ -55,10 +57,7 @@ class LocateVisitsCommandTest extends TestCase
$this->commandTester = $this->testerForCommand($command, $this->downloadDbCommand); $this->commandTester = $this->testerForCommand($command, $this->downloadDbCommand);
} }
/** #[Test, DataProvider('provideArgs')]
* @test
* @dataProvider provideArgs
*/
public function expectedSetOfVisitsIsProcessedBasedOnArgs( public function expectedSetOfVisitsIsProcessedBasedOnArgs(
int $expectedUnlocatedCalls, int $expectedUnlocatedCalls,
int $expectedEmptyCalls, int $expectedEmptyCalls,
@ -100,17 +99,14 @@ class LocateVisitsCommandTest extends TestCase
} }
} }
public function provideArgs(): iterable public static function provideArgs(): iterable
{ {
yield 'no args' => [1, 0, 0, false, []]; yield 'no args' => [1, 0, 0, false, []];
yield 'retry' => [1, 1, 0, false, ['--retry' => true]]; yield 'retry' => [1, 1, 0, false, ['--retry' => true]];
yield 'all' => [0, 0, 1, true, ['--retry' => true, '--all' => true]]; yield 'all' => [0, 0, 1, true, ['--retry' => true, '--all' => true]];
} }
/** #[Test, DataProvider('provideIgnoredAddresses')]
* @test
* @dataProvider provideIgnoredAddresses
*/
public function localhostAndEmptyAddressesAreIgnored(IpCannotBeLocatedException $e, string $message): void public function localhostAndEmptyAddressesAreIgnored(IpCannotBeLocatedException $e, string $message): void
{ {
$visit = Visit::forValidShortUrl(ShortUrl::createFake(), Visitor::emptyInstance()); $visit = Visit::forValidShortUrl(ShortUrl::createFake(), Visitor::emptyInstance());
@ -131,13 +127,13 @@ class LocateVisitsCommandTest extends TestCase
self::assertStringContainsString($message, $output); self::assertStringContainsString($message, $output);
} }
public function provideIgnoredAddresses(): iterable public static function provideIgnoredAddresses(): iterable
{ {
yield 'empty address' => [IpCannotBeLocatedException::forEmptyAddress(), 'Ignored visit with no IP address']; yield 'empty address' => [IpCannotBeLocatedException::forEmptyAddress(), 'Ignored visit with no IP address'];
yield 'localhost address' => [IpCannotBeLocatedException::forLocalhost(), 'Ignored localhost address']; yield 'localhost address' => [IpCannotBeLocatedException::forLocalhost(), 'Ignored localhost address'];
} }
/** @test */ #[Test]
public function errorWhileLocatingIpIsDisplayed(): void public function errorWhileLocatingIpIsDisplayed(): void
{ {
$visit = Visit::forValidShortUrl(ShortUrl::createFake(), new Visitor('', '', '1.2.3.4', '')); $visit = Visit::forValidShortUrl(ShortUrl::createFake(), new Visitor('', '', '1.2.3.4', ''));
@ -168,7 +164,7 @@ class LocateVisitsCommandTest extends TestCase
}; };
} }
/** @test */ #[Test]
public function noActionIsPerformedIfLockIsAcquired(): void public function noActionIsPerformedIfLockIsAcquired(): void
{ {
$this->lock->method('acquire')->with($this->isFalse())->willReturn(false); $this->lock->method('acquire')->with($this->isFalse())->willReturn(false);
@ -186,7 +182,7 @@ class LocateVisitsCommandTest extends TestCase
); );
} }
/** @test */ #[Test]
public function showsProperMessageWhenGeoLiteUpdateFails(): void public function showsProperMessageWhenGeoLiteUpdateFails(): void
{ {
$this->lock->method('acquire')->with($this->isFalse())->willReturn(true); $this->lock->method('acquire')->with($this->isFalse())->willReturn(true);
@ -199,7 +195,7 @@ class LocateVisitsCommandTest extends TestCase
self::assertStringContainsString('It is not possible to locate visits without a GeoLite2 db file.', $output); self::assertStringContainsString('It is not possible to locate visits without a GeoLite2 db file.', $output);
} }
/** @test */ #[Test]
public function providingAllFlagOnItsOwnDisplaysNotice(): void public function providingAllFlagOnItsOwnDisplaysNotice(): void
{ {
$this->lock->method('acquire')->with($this->isFalse())->willReturn(true); $this->lock->method('acquire')->with($this->isFalse())->willReturn(true);
@ -211,10 +207,7 @@ class LocateVisitsCommandTest extends TestCase
self::assertStringContainsString('The --all flag has no effect on its own', $output); self::assertStringContainsString('The --all flag has no effect on its own', $output);
} }
/** #[Test, DataProvider('provideAbortInputs')]
* @test
* @dataProvider provideAbortInputs
*/
public function processingAllCancelsCommandIfUserDoesNotActivelyAgreeToConfirmation(array $inputs): void public function processingAllCancelsCommandIfUserDoesNotActivelyAgreeToConfirmation(array $inputs): void
{ {
$this->downloadDbCommand->method('run')->withAnyParameters()->willReturn(ExitCodes::EXIT_SUCCESS); $this->downloadDbCommand->method('run')->withAnyParameters()->willReturn(ExitCodes::EXIT_SUCCESS);
@ -226,7 +219,7 @@ class LocateVisitsCommandTest extends TestCase
$this->commandTester->execute(['--all' => true, '--retry' => true]); $this->commandTester->execute(['--all' => true, '--retry' => true]);
} }
public function provideAbortInputs(): iterable public static function provideAbortInputs(): iterable
{ {
yield 'n' => [['n']]; yield 'n' => [['n']];
yield 'no' => [['no']]; yield 'no' => [['no']];

View File

@ -5,6 +5,7 @@ declare(strict_types=1);
namespace ShlinkioTest\Shlink\CLI; namespace ShlinkioTest\Shlink\CLI;
use Laminas\ServiceManager\AbstractFactory\ConfigAbstractFactory; use Laminas\ServiceManager\AbstractFactory\ConfigAbstractFactory;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Shlinkio\Shlink\CLI\ConfigProvider; use Shlinkio\Shlink\CLI\ConfigProvider;
@ -17,7 +18,7 @@ class ConfigProviderTest extends TestCase
$this->configProvider = new ConfigProvider(); $this->configProvider = new ConfigProvider();
} }
/** @test */ #[Test]
public function configIsProperlyReturned(): void public function configIsProperlyReturned(): void
{ {
$config = ($this->configProvider)(); $config = ($this->configProvider)();

View File

@ -5,6 +5,8 @@ declare(strict_types=1);
namespace ShlinkioTest\Shlink\CLI\Exception; namespace ShlinkioTest\Shlink\CLI\Exception;
use Exception; use Exception;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use RuntimeException; use RuntimeException;
use Shlinkio\Shlink\CLI\Exception\GeolocationDbUpdateFailedException; use Shlinkio\Shlink\CLI\Exception\GeolocationDbUpdateFailedException;
@ -12,10 +14,7 @@ use Throwable;
class GeolocationDbUpdateFailedExceptionTest extends TestCase class GeolocationDbUpdateFailedExceptionTest extends TestCase
{ {
/** #[Test, DataProvider('providePrev')]
* @test
* @dataProvider providePrev
*/
public function withOlderDbBuildsException(?Throwable $prev): void public function withOlderDbBuildsException(?Throwable $prev): void
{ {
$e = GeolocationDbUpdateFailedException::withOlderDb($prev); $e = GeolocationDbUpdateFailedException::withOlderDb($prev);
@ -29,10 +28,7 @@ class GeolocationDbUpdateFailedExceptionTest extends TestCase
self::assertEquals($prev, $e->getPrevious()); self::assertEquals($prev, $e->getPrevious());
} }
/** #[Test, DataProvider('providePrev')]
* @test
* @dataProvider providePrev
*/
public function withoutOlderDbBuildsException(?Throwable $prev): void public function withoutOlderDbBuildsException(?Throwable $prev): void
{ {
$e = GeolocationDbUpdateFailedException::withoutOlderDb($prev); $e = GeolocationDbUpdateFailedException::withoutOlderDb($prev);
@ -46,14 +42,14 @@ class GeolocationDbUpdateFailedExceptionTest extends TestCase
self::assertEquals($prev, $e->getPrevious()); self::assertEquals($prev, $e->getPrevious());
} }
public function providePrev(): iterable public static function providePrev(): iterable
{ {
yield 'no prev' => [null]; yield 'no prev' => [null];
yield 'RuntimeException' => [new RuntimeException('prev')]; yield 'RuntimeException' => [new RuntimeException('prev')];
yield 'Exception' => [new Exception('prev')]; yield 'Exception' => [new Exception('prev')];
} }
/** @test */ #[Test]
public function withInvalidEpochInOldDbBuildsException(): void public function withInvalidEpochInOldDbBuildsException(): void
{ {
$e = GeolocationDbUpdateFailedException::withInvalidEpochInOldDb('foobar'); $e = GeolocationDbUpdateFailedException::withInvalidEpochInOldDb('foobar');

View File

@ -4,6 +4,7 @@ declare(strict_types=1);
namespace ShlinkioTest\Shlink\CLI\Exception; namespace ShlinkioTest\Shlink\CLI\Exception;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Shlinkio\Shlink\CLI\Exception\InvalidRoleConfigException; use Shlinkio\Shlink\CLI\Exception\InvalidRoleConfigException;
use Shlinkio\Shlink\Rest\ApiKey\Role; use Shlinkio\Shlink\Rest\ApiKey\Role;
@ -12,7 +13,7 @@ use function sprintf;
class InvalidRoleConfigExceptionTest extends TestCase class InvalidRoleConfigExceptionTest extends TestCase
{ {
/** @test */ #[Test]
public function forDomainOnlyWithDefaultDomainGeneratesExpectedException(): void public function forDomainOnlyWithDefaultDomainGeneratesExpectedException(): void
{ {
$e = InvalidRoleConfigException::forDomainOnlyWithDefaultDomain(); $e = InvalidRoleConfigException::forDomainOnlyWithDefaultDomain();

View File

@ -5,6 +5,7 @@ declare(strict_types=1);
namespace ShlinkioTest\Shlink\CLI\Factory; namespace ShlinkioTest\Shlink\CLI\Factory;
use Laminas\ServiceManager\ServiceManager; use Laminas\ServiceManager\ServiceManager;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Shlinkio\Shlink\CLI\Factory\ApplicationFactory; use Shlinkio\Shlink\CLI\Factory\ApplicationFactory;
use Shlinkio\Shlink\Core\Options\AppOptions; use Shlinkio\Shlink\Core\Options\AppOptions;
@ -21,7 +22,7 @@ class ApplicationFactoryTest extends TestCase
$this->factory = new ApplicationFactory(); $this->factory = new ApplicationFactory();
} }
/** @test */ #[Test]
public function allCommandsWhichAreServicesAreAdded(): void public function allCommandsWhichAreServicesAreAdded(): void
{ {
$sm = $this->createServiceManager([ $sm = $this->createServiceManager([

View File

@ -7,6 +7,8 @@ namespace ShlinkioTest\Shlink\CLI\GeoLite;
use Cake\Chronos\Chronos; use Cake\Chronos\Chronos;
use GeoIp2\Database\Reader; use GeoIp2\Database\Reader;
use MaxMind\Db\Reader\Metadata; use MaxMind\Db\Reader\Metadata;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Shlinkio\Shlink\CLI\Exception\GeolocationDbUpdateFailedException; use Shlinkio\Shlink\CLI\Exception\GeolocationDbUpdateFailedException;
@ -35,7 +37,7 @@ class GeolocationDbUpdaterTest extends TestCase
$this->lock->method('acquire')->with($this->isTrue())->willReturn(true); $this->lock->method('acquire')->with($this->isTrue())->willReturn(true);
} }
/** @test */ #[Test]
public function exceptionIsThrownWhenOlderDbDoesNotExistAndDownloadFails(): void public function exceptionIsThrownWhenOlderDbDoesNotExistAndDownloadFails(): void
{ {
$mustBeUpdated = fn () => self::assertTrue(true); $mustBeUpdated = fn () => self::assertTrue(true);
@ -58,10 +60,7 @@ class GeolocationDbUpdaterTest extends TestCase
} }
} }
/** #[Test, DataProvider('provideBigDays')]
* @test
* @dataProvider provideBigDays
*/
public function exceptionIsThrownWhenOlderDbIsTooOldAndDownloadFails(int $days): void public function exceptionIsThrownWhenOlderDbIsTooOldAndDownloadFails(int $days): void
{ {
$prev = new DbUpdateException(''); $prev = new DbUpdateException('');
@ -84,7 +83,7 @@ class GeolocationDbUpdaterTest extends TestCase
} }
} }
public function provideBigDays(): iterable public static function provideBigDays(): iterable
{ {
yield [36]; yield [36];
yield [50]; yield [50];
@ -92,10 +91,7 @@ class GeolocationDbUpdaterTest extends TestCase
yield [100]; yield [100];
} }
/** #[Test, DataProvider('provideSmallDays')]
* @test
* @dataProvider provideSmallDays
*/
public function databaseIsNotUpdatedIfItIsNewEnough(string|int $buildEpoch): void public function databaseIsNotUpdatedIfItIsNewEnough(string|int $buildEpoch): void
{ {
$this->dbUpdater->expects($this->once())->method('databaseFileExists')->willReturn(true); $this->dbUpdater->expects($this->once())->method('databaseFileExists')->willReturn(true);
@ -109,7 +105,7 @@ class GeolocationDbUpdaterTest extends TestCase
self::assertEquals(GeolocationResult::DB_IS_UP_TO_DATE, $result); self::assertEquals(GeolocationResult::DB_IS_UP_TO_DATE, $result);
} }
public function provideSmallDays(): iterable public static function provideSmallDays(): iterable
{ {
$generateParamsWithTimestamp = static function (int $days) { $generateParamsWithTimestamp = static function (int $days) {
$timestamp = Chronos::now()->subDays($days)->getTimestamp(); $timestamp = Chronos::now()->subDays($days)->getTimestamp();
@ -119,7 +115,7 @@ class GeolocationDbUpdaterTest extends TestCase
return map(range(0, 34), $generateParamsWithTimestamp); return map(range(0, 34), $generateParamsWithTimestamp);
} }
/** @test */ #[Test]
public function exceptionIsThrownWhenCheckingExistingDatabaseWithInvalidBuildEpoch(): void public function exceptionIsThrownWhenCheckingExistingDatabaseWithInvalidBuildEpoch(): void
{ {
$this->dbUpdater->expects($this->once())->method('databaseFileExists')->willReturn(true); $this->dbUpdater->expects($this->once())->method('databaseFileExists')->willReturn(true);
@ -151,10 +147,7 @@ class GeolocationDbUpdaterTest extends TestCase
]); ]);
} }
/** #[Test, DataProvider('provideTrackingOptions')]
* @test
* @dataProvider provideTrackingOptions
*/
public function downloadDbIsSkippedIfTrackingIsDisabled(TrackingOptions $options): void public function downloadDbIsSkippedIfTrackingIsDisabled(TrackingOptions $options): void
{ {
$result = $this->geolocationDbUpdater($options)->checkDbUpdate(); $result = $this->geolocationDbUpdater($options)->checkDbUpdate();
@ -164,7 +157,7 @@ class GeolocationDbUpdaterTest extends TestCase
self::assertEquals(GeolocationResult::CHECK_SKIPPED, $result); self::assertEquals(GeolocationResult::CHECK_SKIPPED, $result);
} }
public function provideTrackingOptions(): iterable public static function provideTrackingOptions(): iterable
{ {
yield 'disableTracking' => [new TrackingOptions(disableTracking: true)]; yield 'disableTracking' => [new TrackingOptions(disableTracking: true)];
yield 'disableIpTracking' => [new TrackingOptions(disableIpTracking: true)]; yield 'disableIpTracking' => [new TrackingOptions(disableIpTracking: true)];

View File

@ -4,6 +4,7 @@ declare(strict_types=1);
namespace ShlinkioTest\Shlink\CLI\Util; namespace ShlinkioTest\Shlink\CLI\Util;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Shlinkio\Shlink\CLI\Util\ProcessRunner; use Shlinkio\Shlink\CLI\Util\ProcessRunner;
@ -34,7 +35,7 @@ class ProcessRunnerTest extends TestCase
$this->runner = new ProcessRunner($this->helper, fn () => $this->process); $this->runner = new ProcessRunner($this->helper, fn () => $this->process);
} }
/** @test */ #[Test]
public function noMessagesAreWrittenWhenOutputIsNotVerbose(): void public function noMessagesAreWrittenWhenOutputIsNotVerbose(): void
{ {
$this->output->expects($this->exactly(2))->method('isVeryVerbose')->with()->willReturn(false); $this->output->expects($this->exactly(2))->method('isVeryVerbose')->with()->willReturn(false);
@ -50,7 +51,7 @@ class ProcessRunnerTest extends TestCase
$this->runner->run($this->output, []); $this->runner->run($this->output, []);
} }
/** @test */ #[Test]
public function someMessagesAreWrittenWhenOutputIsVerbose(): void public function someMessagesAreWrittenWhenOutputIsVerbose(): void
{ {
$this->output->expects($this->exactly(2))->method('isVeryVerbose')->with()->willReturn(true); $this->output->expects($this->exactly(2))->method('isVeryVerbose')->with()->willReturn(true);
@ -66,7 +67,7 @@ class ProcessRunnerTest extends TestCase
$this->runner->run($this->output, []); $this->runner->run($this->output, []);
} }
/** @test */ #[Test]
public function wrapsCallbackWhenOutputIsDebug(): void public function wrapsCallbackWhenOutputIsDebug(): void
{ {
$this->output->expects($this->exactly(2))->method('isVeryVerbose')->with()->willReturn(false); $this->output->expects($this->exactly(2))->method('isVeryVerbose')->with()->willReturn(false);

View File

@ -4,6 +4,7 @@ declare(strict_types=1);
namespace ShlinkioTest\Shlink\CLI\Util; namespace ShlinkioTest\Shlink\CLI\Util;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use ReflectionObject; use ReflectionObject;
@ -23,7 +24,7 @@ class ShlinkTableTest extends TestCase
$this->shlinkTable = ShlinkTable::fromBaseTable($this->baseTable); $this->shlinkTable = ShlinkTable::fromBaseTable($this->baseTable);
} }
/** @test */ #[Test]
public function renderMakesTableToBeRenderedWithProvidedInfo(): void public function renderMakesTableToBeRenderedWithProvidedInfo(): void
{ {
$headers = []; $headers = [];
@ -43,7 +44,7 @@ class ShlinkTableTest extends TestCase
$this->shlinkTable->render($headers, $rows, $footerTitle, $headerTitle); $this->shlinkTable->render($headers, $rows, $footerTitle, $headerTitle);
} }
/** @test */ #[Test]
public function newTableIsCreatedForFactoryMethod(): void public function newTableIsCreatedForFactoryMethod(): void
{ {
$instance = ShlinkTable::default($this->createMock(OutputInterface::class)); $instance = ShlinkTable::default($this->createMock(OutputInterface::class));

View File

@ -4,6 +4,8 @@ declare(strict_types=1);
namespace ShlinkioApiTest\Shlink\Core\Action; namespace ShlinkioApiTest\Shlink\Core\Action;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use Shlinkio\Shlink\TestUtils\ApiTest\ApiTestCase; use Shlinkio\Shlink\TestUtils\ApiTest\ApiTestCase;
use const ShlinkioTest\Shlink\ANDROID_USER_AGENT; use const ShlinkioTest\Shlink\ANDROID_USER_AGENT;
@ -12,17 +14,14 @@ use const ShlinkioTest\Shlink\IOS_USER_AGENT;
class RedirectTest extends ApiTestCase class RedirectTest extends ApiTestCase
{ {
/** #[Test, DataProvider('provideUserAgents')]
* @test
* @dataProvider provideUserAgents
*/
public function properRedirectHappensBasedOnUserAgent(?string $userAgent, string $expectedRedirect): void public function properRedirectHappensBasedOnUserAgent(?string $userAgent, string $expectedRedirect): void
{ {
$response = $this->callShortUrl('def456', $userAgent); $response = $this->callShortUrl('def456', $userAgent);
self::assertEquals($expectedRedirect, $response->getHeaderLine('Location')); self::assertEquals($expectedRedirect, $response->getHeaderLine('Location'));
} }
public function provideUserAgents(): iterable public static function provideUserAgents(): iterable
{ {
yield 'android' => [ANDROID_USER_AGENT, 'https://blog.alejandrocelaya.com/android']; yield 'android' => [ANDROID_USER_AGENT, 'https://blog.alejandrocelaya.com/android'];
yield 'ios' => [IOS_USER_AGENT, 'https://blog.alejandrocelaya.com/ios']; yield 'ios' => [IOS_USER_AGENT, 'https://blog.alejandrocelaya.com/ios'];

View File

@ -4,11 +4,12 @@ declare(strict_types=1);
namespace ShlinkioApiTest\Shlink\Core\Action; namespace ShlinkioApiTest\Shlink\Core\Action;
use PHPUnit\Framework\Attributes\Test;
use Shlinkio\Shlink\TestUtils\ApiTest\ApiTestCase; use Shlinkio\Shlink\TestUtils\ApiTest\ApiTestCase;
class RobotsTest extends ApiTestCase class RobotsTest extends ApiTestCase
{ {
/** @test */ #[Test]
public function expectedListOfCrawlableShortCodesIsReturned(): void public function expectedListOfCrawlableShortCodesIsReturned(): void
{ {
$resp = $this->callShortUrl('robots.txt'); $resp = $this->callShortUrl('robots.txt');

View File

@ -6,6 +6,7 @@ namespace ShlinkioDbTest\Shlink\Core\Domain\Repository;
use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection; use Doctrine\Common\Collections\Collection;
use PHPUnit\Framework\Attributes\Test;
use Shlinkio\Shlink\Core\Config\NotFoundRedirects; use Shlinkio\Shlink\Core\Config\NotFoundRedirects;
use Shlinkio\Shlink\Core\Domain\Entity\Domain; use Shlinkio\Shlink\Core\Domain\Entity\Domain;
use Shlinkio\Shlink\Core\Domain\Repository\DomainRepository; use Shlinkio\Shlink\Core\Domain\Repository\DomainRepository;
@ -26,7 +27,7 @@ class DomainRepositoryTest extends DatabaseTestCase
$this->repo = $this->getEntityManager()->getRepository(Domain::class); $this->repo = $this->getEntityManager()->getRepository(Domain::class);
} }
/** @test */ #[Test]
public function expectedDomainsAreFoundWhenNoApiKeyIsInvolved(): void public function expectedDomainsAreFoundWhenNoApiKeyIsInvolved(): void
{ {
$fooDomain = Domain::withAuthority('foo.com'); $fooDomain = Domain::withAuthority('foo.com');
@ -61,7 +62,7 @@ class DomainRepositoryTest extends DatabaseTestCase
self::assertTrue($this->repo->domainExists('detached.com')); self::assertTrue($this->repo->domainExists('detached.com'));
} }
/** @test */ #[Test]
public function expectedDomainsAreFoundWhenApiKeyIsProvided(): void public function expectedDomainsAreFoundWhenApiKeyIsProvided(): void
{ {
$authorApiKey = ApiKey::fromMeta(ApiKeyMeta::withRoles(RoleDefinition::forAuthoredShortUrls())); $authorApiKey = ApiKey::fromMeta(ApiKeyMeta::withRoles(RoleDefinition::forAuthoredShortUrls()));

View File

@ -4,6 +4,7 @@ declare(strict_types=1);
namespace ShlinkioDbTest\Shlink\Core\ShortUrl\Repository; namespace ShlinkioDbTest\Shlink\Core\ShortUrl\Repository;
use PHPUnit\Framework\Attributes\Test;
use Shlinkio\Shlink\Core\ShortUrl\Entity\ShortUrl; use Shlinkio\Shlink\Core\ShortUrl\Entity\ShortUrl;
use Shlinkio\Shlink\Core\ShortUrl\Model\ShortUrlCreation; use Shlinkio\Shlink\Core\ShortUrl\Model\ShortUrlCreation;
use Shlinkio\Shlink\Core\ShortUrl\Repository\CrawlableShortCodesQuery; use Shlinkio\Shlink\Core\ShortUrl\Repository\CrawlableShortCodesQuery;
@ -19,7 +20,7 @@ class CrawlableShortCodesQueryTest extends DatabaseTestCase
$this->query = new CrawlableShortCodesQuery($em, $em->getClassMetadata(ShortUrl::class)); $this->query = new CrawlableShortCodesQuery($em, $em->getClassMetadata(ShortUrl::class));
} }
/** @test */ #[Test]
public function invokingQueryReturnsExpectedResult(): void public function invokingQueryReturnsExpectedResult(): void
{ {
$createShortUrl = fn (bool $crawlable) => ShortUrl::create( $createShortUrl = fn (bool $crawlable) => ShortUrl::create(

View File

@ -6,6 +6,7 @@ namespace ShlinkioDbTest\Shlink\Core\ShortUrl\Repository;
use Cake\Chronos\Chronos; use Cake\Chronos\Chronos;
use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\ArrayCollection;
use PHPUnit\Framework\Attributes\Test;
use ReflectionObject; use ReflectionObject;
use Shlinkio\Shlink\Common\Util\DateRange; use Shlinkio\Shlink\Common\Util\DateRange;
use Shlinkio\Shlink\Core\Model\Ordering; use Shlinkio\Shlink\Core\Model\Ordering;
@ -37,7 +38,7 @@ class ShortUrlListRepositoryTest extends DatabaseTestCase
$this->relationResolver = new PersistenceShortUrlRelationResolver($em); $this->relationResolver = new PersistenceShortUrlRelationResolver($em);
} }
/** @test */ #[Test]
public function countListReturnsProperNumberOfResults(): void public function countListReturnsProperNumberOfResults(): void
{ {
$count = 5; $count = 5;
@ -49,7 +50,7 @@ class ShortUrlListRepositoryTest extends DatabaseTestCase
self::assertEquals($count, $this->repo->countList(new ShortUrlsCountFiltering())); self::assertEquals($count, $this->repo->countList(new ShortUrlsCountFiltering()));
} }
/** @test */ #[Test]
public function findListProperlyFiltersResult(): void public function findListProperlyFiltersResult(): void
{ {
$foo = ShortUrl::create( $foo = ShortUrl::create(
@ -143,7 +144,7 @@ class ShortUrlListRepositoryTest extends DatabaseTestCase
)); ));
} }
/** @test */ #[Test]
public function findListProperlyMapsFieldNamesToColumnNamesWhenOrdering(): void public function findListProperlyMapsFieldNamesToColumnNamesWhenOrdering(): void
{ {
$urls = ['a', 'z', 'c', 'b']; $urls = ['a', 'z', 'c', 'b'];
@ -164,7 +165,7 @@ class ShortUrlListRepositoryTest extends DatabaseTestCase
self::assertEquals('z', $result[3]->getLongUrl()); self::assertEquals('z', $result[3]->getLongUrl());
} }
/** @test */ #[Test]
public function findListReturnsOnlyThoseWithMatchingTags(): void public function findListReturnsOnlyThoseWithMatchingTags(): void
{ {
$shortUrl1 = ShortUrl::create(ShortUrlCreation::fromRawData([ $shortUrl1 = ShortUrl::create(ShortUrlCreation::fromRawData([
@ -273,7 +274,7 @@ class ShortUrlListRepositoryTest extends DatabaseTestCase
)); ));
} }
/** @test */ #[Test]
public function findListReturnsOnlyThoseWithMatchingDomains(): void public function findListReturnsOnlyThoseWithMatchingDomains(): void
{ {
$shortUrl1 = ShortUrl::create(ShortUrlCreation::fromRawData([ $shortUrl1 = ShortUrl::create(ShortUrlCreation::fromRawData([
@ -309,7 +310,7 @@ class ShortUrlListRepositoryTest extends DatabaseTestCase
self::assertCount(0, $this->repo->findList($buildFiltering('no results'))); self::assertCount(0, $this->repo->findList($buildFiltering('no results')));
} }
/** @test */ #[Test]
public function findListReturnsOnlyThoseWithoutExcludedUrls(): void public function findListReturnsOnlyThoseWithoutExcludedUrls(): void
{ {
$shortUrl1 = ShortUrl::create(ShortUrlCreation::fromRawData([ $shortUrl1 = ShortUrl::create(ShortUrlCreation::fromRawData([

View File

@ -5,6 +5,7 @@ declare(strict_types=1);
namespace ShlinkioDbTest\Shlink\Core\ShortUrl\Repository; namespace ShlinkioDbTest\Shlink\Core\ShortUrl\Repository;
use Cake\Chronos\Chronos; use Cake\Chronos\Chronos;
use PHPUnit\Framework\Attributes\Test;
use Shlinkio\Shlink\Core\Domain\Entity\Domain; use Shlinkio\Shlink\Core\Domain\Entity\Domain;
use Shlinkio\Shlink\Core\ShortUrl\Entity\ShortUrl; use Shlinkio\Shlink\Core\ShortUrl\Entity\ShortUrl;
use Shlinkio\Shlink\Core\ShortUrl\Model\ShortUrlCreation; use Shlinkio\Shlink\Core\ShortUrl\Model\ShortUrlCreation;
@ -30,7 +31,7 @@ class ShortUrlRepositoryTest extends DatabaseTestCase
$this->relationResolver = new PersistenceShortUrlRelationResolver($this->getEntityManager()); $this->relationResolver = new PersistenceShortUrlRelationResolver($this->getEntityManager());
} }
/** @test */ #[Test]
public function findOneWithDomainFallbackReturnsProperData(): void public function findOneWithDomainFallbackReturnsProperData(): void
{ {
$regularOne = ShortUrl::create(ShortUrlCreation::fromRawData(['customSlug' => 'Foo', 'longUrl' => 'foo'])); $regularOne = ShortUrl::create(ShortUrlCreation::fromRawData(['customSlug' => 'Foo', 'longUrl' => 'foo']));
@ -97,7 +98,7 @@ class ShortUrlRepositoryTest extends DatabaseTestCase
)); ));
} }
/** @test */ #[Test]
public function shortCodeIsInUseLooksForShortUrlInProperSetOfTables(): void public function shortCodeIsInUseLooksForShortUrlInProperSetOfTables(): void
{ {
$shortUrlWithoutDomain = ShortUrl::create( $shortUrlWithoutDomain = ShortUrl::create(
@ -126,7 +127,7 @@ class ShortUrlRepositoryTest extends DatabaseTestCase
)); ));
} }
/** @test */ #[Test]
public function findOneLooksForShortUrlInProperSetOfTables(): void public function findOneLooksForShortUrlInProperSetOfTables(): void
{ {
$shortUrlWithoutDomain = ShortUrl::create( $shortUrlWithoutDomain = ShortUrl::create(
@ -153,7 +154,7 @@ class ShortUrlRepositoryTest extends DatabaseTestCase
)); ));
} }
/** @test */ #[Test]
public function findOneMatchingReturnsNullForNonExistingShortUrls(): void public function findOneMatchingReturnsNullForNonExistingShortUrls(): void
{ {
self::assertNull($this->repo->findOneMatching(ShortUrlCreation::fromRawData(['longUrl' => 'foobar']))); self::assertNull($this->repo->findOneMatching(ShortUrlCreation::fromRawData(['longUrl' => 'foobar'])));
@ -168,7 +169,7 @@ class ShortUrlRepositoryTest extends DatabaseTestCase
]))); ])));
} }
/** @test */ #[Test]
public function findOneMatchingAppliesProperConditions(): void public function findOneMatchingAppliesProperConditions(): void
{ {
$start = Chronos::parse('2020-03-05 20:18:30'); $start = Chronos::parse('2020-03-05 20:18:30');
@ -237,7 +238,7 @@ class ShortUrlRepositoryTest extends DatabaseTestCase
); );
} }
/** @test */ #[Test]
public function findOneMatchingReturnsOldestOneWhenThereAreMultipleMatches(): void public function findOneMatchingReturnsOldestOneWhenThereAreMultipleMatches(): void
{ {
$start = Chronos::parse('2020-03-05 20:18:30'); $start = Chronos::parse('2020-03-05 20:18:30');
@ -265,7 +266,7 @@ class ShortUrlRepositoryTest extends DatabaseTestCase
self::assertNotSame($shortUrl3, $result); self::assertNotSame($shortUrl3, $result);
} }
/** @test */ #[Test]
public function findOneMatchingAppliesProvidedApiKeyConditions(): void public function findOneMatchingAppliesProvidedApiKeyConditions(): void
{ {
$start = Chronos::parse('2020-03-05 20:18:30'); $start = Chronos::parse('2020-03-05 20:18:30');
@ -391,7 +392,7 @@ class ShortUrlRepositoryTest extends DatabaseTestCase
); );
} }
/** @test */ #[Test]
public function importedShortUrlsAreFoundWhenExpected(): void public function importedShortUrlsAreFoundWhenExpected(): void
{ {
$buildImported = static fn (string $shortCode, ?String $domain = null) => $buildImported = static fn (string $shortCode, ?String $domain = null) =>

View File

@ -4,6 +4,8 @@ declare(strict_types=1);
namespace ShlinkioDbTest\Shlink\Core\Tag\Paginator\Adapter; namespace ShlinkioDbTest\Shlink\Core\Tag\Paginator\Adapter;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use Shlinkio\Shlink\Core\Tag\Entity\Tag; use Shlinkio\Shlink\Core\Tag\Entity\Tag;
use Shlinkio\Shlink\Core\Tag\Model\TagsParams; use Shlinkio\Shlink\Core\Tag\Model\TagsParams;
use Shlinkio\Shlink\Core\Tag\Paginator\Adapter\TagsPaginatorAdapter; use Shlinkio\Shlink\Core\Tag\Paginator\Adapter\TagsPaginatorAdapter;
@ -24,9 +26,8 @@ class TagsPaginatorAdapterTest extends DatabaseTestCase
/** /**
* @param int<0, max> $offset * @param int<0, max> $offset
* @param int<0, max> $length * @param int<0, max> $length
* @test
* @dataProvider provideFilters
*/ */
#[Test, DataProvider('provideFilters')]
public function expectedListOfTagsIsReturned( public function expectedListOfTagsIsReturned(
?string $searchTerm, ?string $searchTerm,
?string $orderBy, ?string $orderBy,
@ -52,7 +53,7 @@ class TagsPaginatorAdapterTest extends DatabaseTestCase
self::assertEquals($expectedTotalCount, $adapter->getNbResults()); self::assertEquals($expectedTotalCount, $adapter->getNbResults());
} }
public function provideFilters(): iterable public static function provideFilters(): iterable
{ {
yield [null, null, 0, 10, ['another', 'bar', 'baz', 'foo'], 4]; yield [null, null, 0, 10, ['another', 'bar', 'baz', 'foo'], 4];
yield [null, null, 2, 10, ['baz', 'foo'], 4]; yield [null, null, 2, 10, ['baz', 'foo'], 4];

View File

@ -4,6 +4,8 @@ declare(strict_types=1);
namespace ShlinkioDbTest\Shlink\Core\Tag\Repository; namespace ShlinkioDbTest\Shlink\Core\Tag\Repository;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use Shlinkio\Shlink\Core\Domain\Entity\Domain; use Shlinkio\Shlink\Core\Domain\Entity\Domain;
use Shlinkio\Shlink\Core\Model\Ordering; use Shlinkio\Shlink\Core\Model\Ordering;
use Shlinkio\Shlink\Core\ShortUrl\Entity\ShortUrl; use Shlinkio\Shlink\Core\ShortUrl\Entity\ShortUrl;
@ -34,13 +36,13 @@ class TagRepositoryTest extends DatabaseTestCase
$this->relationResolver = new PersistenceShortUrlRelationResolver($this->getEntityManager()); $this->relationResolver = new PersistenceShortUrlRelationResolver($this->getEntityManager());
} }
/** @test */ #[Test]
public function deleteByNameDoesNothingWhenEmptyListIsProvided(): void public function deleteByNameDoesNothingWhenEmptyListIsProvided(): void
{ {
self::assertEquals(0, $this->repo->deleteByName([])); self::assertEquals(0, $this->repo->deleteByName([]));
} }
/** @test */ #[Test]
public function allTagsWhichMatchNameAreDeleted(): void public function allTagsWhichMatchNameAreDeleted(): void
{ {
$names = ['foo', 'bar', 'baz']; $names = ['foo', 'bar', 'baz'];
@ -54,10 +56,7 @@ class TagRepositoryTest extends DatabaseTestCase
self::assertEquals(2, $this->repo->deleteByName($toDelete)); self::assertEquals(2, $this->repo->deleteByName($toDelete));
} }
/** #[Test, DataProvider('provideFilters')]
* @test
* @dataProvider provideFilters
*/
public function properTagsInfoIsReturned(?TagsListFiltering $filtering, array $expectedList): void public function properTagsInfoIsReturned(?TagsListFiltering $filtering, array $expectedList): void
{ {
$names = ['foo', 'bar', 'baz', 'another']; $names = ['foo', 'bar', 'baz', 'another'];
@ -109,7 +108,7 @@ class TagRepositoryTest extends DatabaseTestCase
} }
} }
public function provideFilters(): iterable public static function provideFilters(): iterable
{ {
$defaultList = [ $defaultList = [
['another', 0, 0, 0], ['another', 0, 0, 0],
@ -221,7 +220,7 @@ class TagRepositoryTest extends DatabaseTestCase
]]; ]];
} }
/** @test */ #[Test]
public function tagExistsReturnsExpectedResultBasedOnApiKey(): void public function tagExistsReturnsExpectedResultBasedOnApiKey(): void
{ {
$domain = Domain::withAuthority('foo.com'); $domain = Domain::withAuthority('foo.com');

View File

@ -4,6 +4,8 @@ declare(strict_types=1);
namespace ShlinkioDbTest\Shlink\Core\Visit\Repository; namespace ShlinkioDbTest\Shlink\Core\Visit\Repository;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use Shlinkio\Shlink\Core\ShortUrl\Entity\ShortUrl; use Shlinkio\Shlink\Core\ShortUrl\Entity\ShortUrl;
use Shlinkio\Shlink\Core\Visit\Entity\Visit; use Shlinkio\Shlink\Core\Visit\Entity\Visit;
use Shlinkio\Shlink\Core\Visit\Entity\VisitLocation; use Shlinkio\Shlink\Core\Visit\Entity\VisitLocation;
@ -25,10 +27,7 @@ class VisitLocationRepositoryTest extends DatabaseTestCase
$this->repo = new VisitLocationRepository($em, $em->getClassMetadata(Visit::class)); $this->repo = new VisitLocationRepository($em, $em->getClassMetadata(Visit::class));
} }
/** #[Test, DataProvider('provideBlockSize')]
* @test
* @dataProvider provideBlockSize
*/
public function findVisitsReturnsProperVisits(int $blockSize): void public function findVisitsReturnsProperVisits(int $blockSize): void
{ {
$shortUrl = ShortUrl::createFake(); $shortUrl = ShortUrl::createFake();
@ -56,7 +55,7 @@ class VisitLocationRepositoryTest extends DatabaseTestCase
self::assertCount(6, [...$all]); self::assertCount(6, [...$all]);
} }
public function provideBlockSize(): iterable public static function provideBlockSize(): iterable
{ {
return map(range(1, 10), fn (int $value) => [$value]); return map(range(1, 10), fn (int $value) => [$value]);
} }

View File

@ -5,6 +5,7 @@ declare(strict_types=1);
namespace ShlinkioDbTest\Shlink\Core\Visit\Repository; namespace ShlinkioDbTest\Shlink\Core\Visit\Repository;
use Cake\Chronos\Chronos; use Cake\Chronos\Chronos;
use PHPUnit\Framework\Attributes\Test;
use ReflectionObject; use ReflectionObject;
use Shlinkio\Shlink\Common\Util\DateRange; use Shlinkio\Shlink\Common\Util\DateRange;
use Shlinkio\Shlink\Core\Domain\Entity\Domain; use Shlinkio\Shlink\Core\Domain\Entity\Domain;
@ -40,7 +41,7 @@ class VisitRepositoryTest extends DatabaseTestCase
$this->relationResolver = new PersistenceShortUrlRelationResolver($this->getEntityManager()); $this->relationResolver = new PersistenceShortUrlRelationResolver($this->getEntityManager());
} }
/** @test */ #[Test]
public function findVisitsByShortCodeReturnsProperData(): void public function findVisitsByShortCodeReturnsProperData(): void
{ {
[$shortCode, $domain] = $this->createShortUrlsAndVisits(); [$shortCode, $domain] = $this->createShortUrlsAndVisits();
@ -89,7 +90,7 @@ class VisitRepositoryTest extends DatabaseTestCase
)); ));
} }
/** @test */ #[Test]
public function countVisitsByShortCodeReturnsProperData(): void public function countVisitsByShortCodeReturnsProperData(): void
{ {
[$shortCode, $domain] = $this->createShortUrlsAndVisits(); [$shortCode, $domain] = $this->createShortUrlsAndVisits();
@ -126,7 +127,7 @@ class VisitRepositoryTest extends DatabaseTestCase
)); ));
} }
/** @test */ #[Test]
public function findVisitsByShortCodeReturnsProperDataWhenUsingAPiKeys(): void public function findVisitsByShortCodeReturnsProperDataWhenUsingAPiKeys(): void
{ {
$adminApiKey = ApiKey::create(); $adminApiKey = ApiKey::create();
@ -158,7 +159,7 @@ class VisitRepositoryTest extends DatabaseTestCase
)); ));
} }
/** @test */ #[Test]
public function findVisitsByTagReturnsProperData(): void public function findVisitsByTagReturnsProperData(): void
{ {
$foo = 'foo'; $foo = 'foo';
@ -183,7 +184,7 @@ class VisitRepositoryTest extends DatabaseTestCase
))); )));
} }
/** @test */ #[Test]
public function countVisitsByTagReturnsProperData(): void public function countVisitsByTagReturnsProperData(): void
{ {
$foo = 'foo'; $foo = 'foo';
@ -205,7 +206,7 @@ class VisitRepositoryTest extends DatabaseTestCase
))); )));
} }
/** @test */ #[Test]
public function findVisitsByDomainReturnsProperData(): void public function findVisitsByDomainReturnsProperData(): void
{ {
$this->createShortUrlsAndVisits('s.test'); $this->createShortUrlsAndVisits('s.test');
@ -229,7 +230,7 @@ class VisitRepositoryTest extends DatabaseTestCase
))); )));
} }
/** @test */ #[Test]
public function countVisitsByDomainReturnsProperData(): void public function countVisitsByDomainReturnsProperData(): void
{ {
$this->createShortUrlsAndVisits('s.test'); $this->createShortUrlsAndVisits('s.test');
@ -253,7 +254,7 @@ class VisitRepositoryTest extends DatabaseTestCase
))); )));
} }
/** @test */ #[Test]
public function countVisitsReturnsExpectedResultBasedOnApiKey(): void public function countVisitsReturnsExpectedResultBasedOnApiKey(): void
{ {
$domain = Domain::withAuthority('foo.com'); $domain = Domain::withAuthority('foo.com');
@ -316,7 +317,7 @@ class VisitRepositoryTest extends DatabaseTestCase
self::assertEquals(3, $this->repo->countOrphanVisits(new VisitsCountFiltering(null, true))); self::assertEquals(3, $this->repo->countOrphanVisits(new VisitsCountFiltering(null, true)));
} }
/** @test */ #[Test]
public function findOrphanVisitsReturnsExpectedResult(): void public function findOrphanVisitsReturnsExpectedResult(): void
{ {
$shortUrl = ShortUrl::create(ShortUrlCreation::fromRawData(['longUrl' => 'longUrl'])); $shortUrl = ShortUrl::create(ShortUrlCreation::fromRawData(['longUrl' => 'longUrl']));
@ -365,7 +366,7 @@ class VisitRepositoryTest extends DatabaseTestCase
))); )));
} }
/** @test */ #[Test]
public function countOrphanVisitsReturnsExpectedResult(): void public function countOrphanVisitsReturnsExpectedResult(): void
{ {
$shortUrl = ShortUrl::create(ShortUrlCreation::fromRawData(['longUrl' => 'longUrl'])); $shortUrl = ShortUrl::create(ShortUrlCreation::fromRawData(['longUrl' => 'longUrl']));
@ -402,7 +403,7 @@ class VisitRepositoryTest extends DatabaseTestCase
)); ));
} }
/** @test */ #[Test]
public function findNonOrphanVisitsReturnsExpectedResult(): void public function findNonOrphanVisitsReturnsExpectedResult(): void
{ {
$shortUrl = ShortUrl::create(ShortUrlCreation::fromRawData(['longUrl' => '1'])); $shortUrl = ShortUrl::create(ShortUrlCreation::fromRawData(['longUrl' => '1']));
@ -445,7 +446,7 @@ class VisitRepositoryTest extends DatabaseTestCase
self::assertCount(5, $this->repo->findNonOrphanVisits(new VisitsListFiltering(null, false, null, 5, 5))); self::assertCount(5, $this->repo->findNonOrphanVisits(new VisitsListFiltering(null, false, null, 5, 5)));
} }
/** @test */ #[Test]
public function findMostRecentOrphanVisitReturnsExpectedVisit(): void public function findMostRecentOrphanVisitReturnsExpectedVisit(): void
{ {
$this->assertNull($this->repo->findMostRecentOrphanVisit()); $this->assertNull($this->repo->findMostRecentOrphanVisit());

View File

@ -5,6 +5,7 @@ declare(strict_types=1);
namespace ShlinkioTest\Shlink\Core\Action; namespace ShlinkioTest\Shlink\Core\Action;
use Laminas\Diactoros\ServerRequest; use Laminas\Diactoros\ServerRequest;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Psr\Http\Server\RequestHandlerInterface; use Psr\Http\Server\RequestHandlerInterface;
@ -29,7 +30,7 @@ class PixelActionTest extends TestCase
$this->action = new PixelAction($this->urlResolver, $this->requestTracker); $this->action = new PixelAction($this->urlResolver, $this->requestTracker);
} }
/** @test */ #[Test]
public function imageIsReturned(): void public function imageIsReturned(): void
{ {
$shortCode = 'abc123'; $shortCode = 'abc123';

View File

@ -7,6 +7,8 @@ namespace ShlinkioTest\Shlink\Core\Action;
use Laminas\Diactoros\Response; use Laminas\Diactoros\Response;
use Laminas\Diactoros\ServerRequest; use Laminas\Diactoros\ServerRequest;
use Laminas\Diactoros\ServerRequestFactory; use Laminas\Diactoros\ServerRequestFactory;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ServerRequestInterface;
@ -37,7 +39,7 @@ class QrCodeActionTest extends TestCase
$this->urlResolver = $this->createMock(ShortUrlResolverInterface::class); $this->urlResolver = $this->createMock(ShortUrlResolverInterface::class);
} }
/** @test */ #[Test]
public function aNotFoundShortCodeWillDelegateIntoNextMiddleware(): void public function aNotFoundShortCodeWillDelegateIntoNextMiddleware(): void
{ {
$shortCode = 'abc123'; $shortCode = 'abc123';
@ -50,7 +52,7 @@ class QrCodeActionTest extends TestCase
$this->action()->process((new ServerRequest())->withAttribute('shortCode', $shortCode), $delegate); $this->action()->process((new ServerRequest())->withAttribute('shortCode', $shortCode), $delegate);
} }
/** @test */ #[Test]
public function aCorrectRequestReturnsTheQrCodeResponse(): void public function aCorrectRequestReturnsTheQrCodeResponse(): void
{ {
$shortCode = 'abc123'; $shortCode = 'abc123';
@ -66,10 +68,7 @@ class QrCodeActionTest extends TestCase
self::assertEquals(200, $resp->getStatusCode()); self::assertEquals(200, $resp->getStatusCode());
} }
/** #[Test, DataProvider('provideQueries')]
* @test
* @dataProvider provideQueries
*/
public function imageIsReturnedWithExpectedContentTypeBasedOnProvidedFormat( public function imageIsReturnedWithExpectedContentTypeBasedOnProvidedFormat(
string $defaultFormat, string $defaultFormat,
array $query, array $query,
@ -87,7 +86,7 @@ class QrCodeActionTest extends TestCase
self::assertEquals($expectedContentType, $resp->getHeaderLine('Content-Type')); self::assertEquals($expectedContentType, $resp->getHeaderLine('Content-Type'));
} }
public function provideQueries(): iterable public static function provideQueries(): iterable
{ {
yield 'no format, png default' => ['png', [], 'image/png']; yield 'no format, png default' => ['png', [], 'image/png'];
yield 'no format, svg default' => ['svg', [], 'image/svg+xml']; yield 'no format, svg default' => ['svg', [], 'image/svg+xml'];
@ -99,10 +98,7 @@ class QrCodeActionTest extends TestCase
yield 'unsupported format, svg default' => ['svg', ['format' => 'jpg'], 'image/svg+xml']; yield 'unsupported format, svg default' => ['svg', ['format' => 'jpg'], 'image/svg+xml'];
} }
/** #[Test, DataProvider('provideRequestsWithSize')]
* @test
* @dataProvider provideRequestsWithSize
*/
public function imageIsReturnedWithExpectedSize( public function imageIsReturnedWithExpectedSize(
QrCodeOptions $defaultOptions, QrCodeOptions $defaultOptions,
ServerRequestInterface $req, ServerRequestInterface $req,
@ -122,7 +118,7 @@ class QrCodeActionTest extends TestCase
self::assertEquals($expectedSize, $size); self::assertEquals($expectedSize, $size);
} }
public function provideRequestsWithSize(): iterable public static function provideRequestsWithSize(): iterable
{ {
yield 'different margin and size defaults' => [ yield 'different margin and size defaults' => [
new QrCodeOptions(size: 660, margin: 40), new QrCodeOptions(size: 660, margin: 40),
@ -188,10 +184,7 @@ class QrCodeActionTest extends TestCase
]; ];
} }
/** #[Test, DataProvider('provideRoundBlockSize')]
* @test
* @dataProvider provideRoundBlockSize
*/
public function imageCanRemoveExtraMarginWhenBlockRoundIsDisabled( public function imageCanRemoveExtraMarginWhenBlockRoundIsDisabled(
QrCodeOptions $defaultOptions, QrCodeOptions $defaultOptions,
?string $roundBlockSize, ?string $roundBlockSize,
@ -215,7 +208,7 @@ class QrCodeActionTest extends TestCase
self::assertEquals($color, $expectedColor); self::assertEquals($color, $expectedColor);
} }
public function provideRoundBlockSize(): iterable public static function provideRoundBlockSize(): iterable
{ {
yield 'no round block param' => [new QrCodeOptions(), null, self::WHITE]; yield 'no round block param' => [new QrCodeOptions(), null, self::WHITE];
yield 'no round block param, but disabled by default' => [ yield 'no round block param, but disabled by default' => [

View File

@ -6,6 +6,7 @@ namespace ShlinkioTest\Shlink\Core\Action;
use Laminas\Diactoros\Response; use Laminas\Diactoros\Response;
use Laminas\Diactoros\ServerRequest; use Laminas\Diactoros\ServerRequest;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Psr\Http\Server\RequestHandlerInterface; use Psr\Http\Server\RequestHandlerInterface;
@ -44,7 +45,7 @@ class RedirectActionTest extends TestCase
); );
} }
/** @test */ #[Test]
public function redirectionIsPerformedToLongUrl(): void public function redirectionIsPerformedToLongUrl(): void
{ {
$shortCode = 'abc123'; $shortCode = 'abc123';
@ -64,7 +65,7 @@ class RedirectActionTest extends TestCase
self::assertSame($expectedResp, $response); self::assertSame($expectedResp, $response);
} }
/** @test */ #[Test]
public function nextMiddlewareIsInvokedIfLongUrlIsNotFound(): void public function nextMiddlewareIsInvokedIfLongUrlIsNotFound(): void
{ {
$shortCode = 'abc123'; $shortCode = 'abc123';

View File

@ -5,6 +5,8 @@ declare(strict_types=1);
namespace ShlinkioTest\Shlink\Core\Action; namespace ShlinkioTest\Shlink\Core\Action;
use Laminas\Diactoros\ServerRequestFactory; use Laminas\Diactoros\ServerRequestFactory;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Shlinkio\Shlink\Core\Action\RobotsAction; use Shlinkio\Shlink\Core\Action\RobotsAction;
@ -21,10 +23,7 @@ class RobotsActionTest extends TestCase
$this->action = new RobotsAction($this->helper); $this->action = new RobotsAction($this->helper);
} }
/** #[Test, DataProvider('provideShortCodes')]
* @test
* @dataProvider provideShortCodes
*/
public function buildsRobotsLinesFromCrawlableShortCodes(array $shortCodes, string $expected): void public function buildsRobotsLinesFromCrawlableShortCodes(array $shortCodes, string $expected): void
{ {
$this->helper $this->helper
@ -39,7 +38,7 @@ class RobotsActionTest extends TestCase
self::assertEquals('text/plain', $response->getHeaderLine('Content-Type')); self::assertEquals('text/plain', $response->getHeaderLine('Content-Type'));
} }
public function provideShortCodes(): iterable public static function provideShortCodes(): iterable
{ {
yield 'three short codes' => [['foo', 'bar', 'baz'], <<<ROBOTS yield 'three short codes' => [['foo', 'bar', 'baz'], <<<ROBOTS
# For more information about the robots.txt standard, see: # For more information about the robots.txt standard, see:

View File

@ -4,6 +4,7 @@ declare(strict_types=1);
namespace ShlinkioTest\Shlink\Core\Config; namespace ShlinkioTest\Shlink\Core\Config;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Shlinkio\Shlink\Core\Config\EmptyNotFoundRedirectConfig; use Shlinkio\Shlink\Core\Config\EmptyNotFoundRedirectConfig;
@ -16,7 +17,7 @@ class EmptyNotFoundRedirectConfigTest extends TestCase
$this->redirectsConfig = new EmptyNotFoundRedirectConfig(); $this->redirectsConfig = new EmptyNotFoundRedirectConfig();
} }
/** @test */ #[Test]
public function allMethodsReturnHardcodedValues(): void public function allMethodsReturnHardcodedValues(): void
{ {
self::assertNull($this->redirectsConfig->invalidShortUrlRedirect()); self::assertNull($this->redirectsConfig->invalidShortUrlRedirect());

View File

@ -4,6 +4,8 @@ declare(strict_types=1);
namespace ShlinkioTest\Shlink\Core\Config; namespace ShlinkioTest\Shlink\Core\Config;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Shlinkio\Shlink\Core\Config\EnvVars; use Shlinkio\Shlink\Core\Config\EnvVars;
@ -23,16 +25,13 @@ class EnvVarsTest extends TestCase
putenv(EnvVars::DB_NAME->value . '='); putenv(EnvVars::DB_NAME->value . '=');
} }
/** #[Test, DataProvider('provideExistingEnvVars')]
* @test
* @dataProvider provideExistingEnvVars
*/
public function existsInEnvReturnsExpectedValue(EnvVars $envVar, bool $exists): void public function existsInEnvReturnsExpectedValue(EnvVars $envVar, bool $exists): void
{ {
self::assertEquals($exists, $envVar->existsInEnv()); self::assertEquals($exists, $envVar->existsInEnv());
} }
public function provideExistingEnvVars(): iterable public static function provideExistingEnvVars(): iterable
{ {
yield 'DB_NAME' => [EnvVars::DB_NAME, true]; yield 'DB_NAME' => [EnvVars::DB_NAME, true];
yield 'BASE_PATH' => [EnvVars::BASE_PATH, true]; yield 'BASE_PATH' => [EnvVars::BASE_PATH, true];
@ -40,16 +39,13 @@ class EnvVarsTest extends TestCase
yield 'DEFAULT_REGULAR_404_REDIRECT' => [EnvVars::DEFAULT_REGULAR_404_REDIRECT, false]; yield 'DEFAULT_REGULAR_404_REDIRECT' => [EnvVars::DEFAULT_REGULAR_404_REDIRECT, false];
} }
/** #[Test, DataProvider('provideEnvVarsValues')]
* @test
* @dataProvider provideEnvVarsValues
*/
public function expectedValueIsLoadedFromEnv(EnvVars $envVar, mixed $expected, mixed $default): void public function expectedValueIsLoadedFromEnv(EnvVars $envVar, mixed $expected, mixed $default): void
{ {
self::assertEquals($expected, $envVar->loadFromEnv($default)); self::assertEquals($expected, $envVar->loadFromEnv($default));
} }
public function provideEnvVarsValues(): iterable public static function provideEnvVarsValues(): iterable
{ {
yield 'DB_NAME without default' => [EnvVars::DB_NAME, 'shlink', null]; yield 'DB_NAME without default' => [EnvVars::DB_NAME, 'shlink', null];
yield 'DB_NAME with default' => [EnvVars::DB_NAME, 'shlink', 'foobar']; yield 'DB_NAME with default' => [EnvVars::DB_NAME, 'shlink', 'foobar'];

View File

@ -9,11 +9,12 @@ use Laminas\Diactoros\ServerRequestFactory;
use Laminas\Diactoros\Uri; use Laminas\Diactoros\Uri;
use Mezzio\Router\Route; use Mezzio\Router\Route;
use Mezzio\Router\RouteResult; use Mezzio\Router\RouteResult;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\UriInterface; use Psr\Http\Message\UriInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Log\NullLogger; use Psr\Log\NullLogger;
use Shlinkio\Shlink\Core\Action\RedirectAction; use Shlinkio\Shlink\Core\Action\RedirectAction;
use Shlinkio\Shlink\Core\Config\NotFoundRedirectResolver; use Shlinkio\Shlink\Core\Config\NotFoundRedirectResolver;
@ -21,6 +22,8 @@ use Shlinkio\Shlink\Core\ErrorHandler\Model\NotFoundType;
use Shlinkio\Shlink\Core\Options\NotFoundRedirectOptions; use Shlinkio\Shlink\Core\Options\NotFoundRedirectOptions;
use Shlinkio\Shlink\Core\Util\RedirectResponseHelperInterface; use Shlinkio\Shlink\Core\Util\RedirectResponseHelperInterface;
use function Laminas\Stratigility\middleware;
class NotFoundRedirectResolverTest extends TestCase class NotFoundRedirectResolverTest extends TestCase
{ {
private NotFoundRedirectResolver $resolver; private NotFoundRedirectResolver $resolver;
@ -32,10 +35,7 @@ class NotFoundRedirectResolverTest extends TestCase
$this->resolver = new NotFoundRedirectResolver($this->helper, new NullLogger()); $this->resolver = new NotFoundRedirectResolver($this->helper, new NullLogger());
} }
/** #[Test, DataProvider('provideRedirects')]
* @test
* @dataProvider provideRedirects
*/
public function expectedRedirectionIsReturnedDependingOnTheCase( public function expectedRedirectionIsReturnedDependingOnTheCase(
UriInterface $uri, UriInterface $uri,
NotFoundType $notFoundType, NotFoundType $notFoundType,
@ -52,47 +52,47 @@ class NotFoundRedirectResolverTest extends TestCase
self::assertSame($expectedResp, $resp); self::assertSame($expectedResp, $resp);
} }
public function provideRedirects(): iterable public static function provideRedirects(): iterable
{ {
yield 'base URL with trailing slash' => [ yield 'base URL with trailing slash' => [
$uri = new Uri('/'), $uri = new Uri('/'),
$this->notFoundType(ServerRequestFactory::fromGlobals()->withUri($uri)), self::notFoundType(ServerRequestFactory::fromGlobals()->withUri($uri)),
new NotFoundRedirectOptions(baseUrl: 'baseUrl'), new NotFoundRedirectOptions(baseUrl: 'baseUrl'),
'baseUrl', 'baseUrl',
]; ];
yield 'base URL with domain placeholder' => [ yield 'base URL with domain placeholder' => [
$uri = new Uri('https://s.test'), $uri = new Uri('https://s.test'),
$this->notFoundType(ServerRequestFactory::fromGlobals()->withUri($uri)), self::notFoundType(ServerRequestFactory::fromGlobals()->withUri($uri)),
new NotFoundRedirectOptions(baseUrl: 'https://redirect-here.com/{DOMAIN}'), new NotFoundRedirectOptions(baseUrl: 'https://redirect-here.com/{DOMAIN}'),
'https://redirect-here.com/s.test', 'https://redirect-here.com/s.test',
]; ];
yield 'base URL with domain placeholder in query' => [ yield 'base URL with domain placeholder in query' => [
$uri = new Uri('https://s.test'), $uri = new Uri('https://s.test'),
$this->notFoundType(ServerRequestFactory::fromGlobals()->withUri($uri)), self::notFoundType(ServerRequestFactory::fromGlobals()->withUri($uri)),
new NotFoundRedirectOptions(baseUrl: 'https://redirect-here.com/?domain={DOMAIN}'), new NotFoundRedirectOptions(baseUrl: 'https://redirect-here.com/?domain={DOMAIN}'),
'https://redirect-here.com/?domain=s.test', 'https://redirect-here.com/?domain=s.test',
]; ];
yield 'base URL without trailing slash' => [ yield 'base URL without trailing slash' => [
$uri = new Uri(''), $uri = new Uri(''),
$this->notFoundType(ServerRequestFactory::fromGlobals()->withUri($uri)), self::notFoundType(ServerRequestFactory::fromGlobals()->withUri($uri)),
new NotFoundRedirectOptions(baseUrl: 'baseUrl'), new NotFoundRedirectOptions(baseUrl: 'baseUrl'),
'baseUrl', 'baseUrl',
]; ];
yield 'regular 404' => [ yield 'regular 404' => [
$uri = new Uri('/foo/bar'), $uri = new Uri('/foo/bar'),
$this->notFoundType(ServerRequestFactory::fromGlobals()->withUri($uri)), self::notFoundType(ServerRequestFactory::fromGlobals()->withUri($uri)),
new NotFoundRedirectOptions(regular404: 'regular404'), new NotFoundRedirectOptions(regular404: 'regular404'),
'regular404', 'regular404',
]; ];
yield 'regular 404 with path placeholder in query' => [ yield 'regular 404 with path placeholder in query' => [
$uri = new Uri('/foo/bar'), $uri = new Uri('/foo/bar'),
$this->notFoundType(ServerRequestFactory::fromGlobals()->withUri($uri)), self::notFoundType(ServerRequestFactory::fromGlobals()->withUri($uri)),
new NotFoundRedirectOptions(regular404: 'https://redirect-here.com/?path={ORIGINAL_PATH}'), new NotFoundRedirectOptions(regular404: 'https://redirect-here.com/?path={ORIGINAL_PATH}'),
'https://redirect-here.com/?path=%2Ffoo%2Fbar', 'https://redirect-here.com/?path=%2Ffoo%2Fbar',
]; ];
yield 'regular 404 with multiple placeholders' => [ yield 'regular 404 with multiple placeholders' => [
$uri = new Uri('https://s.test/foo/bar'), $uri = new Uri('https://s.test/foo/bar'),
$this->notFoundType(ServerRequestFactory::fromGlobals()->withUri($uri)), self::notFoundType(ServerRequestFactory::fromGlobals()->withUri($uri)),
new NotFoundRedirectOptions( new NotFoundRedirectOptions(
regular404: 'https://redirect-here.com/{ORIGINAL_PATH}/{DOMAIN}/?d={DOMAIN}&p={ORIGINAL_PATH}', regular404: 'https://redirect-here.com/{ORIGINAL_PATH}/{DOMAIN}/?d={DOMAIN}&p={ORIGINAL_PATH}',
), ),
@ -100,22 +100,22 @@ class NotFoundRedirectResolverTest extends TestCase
]; ];
yield 'invalid short URL' => [ yield 'invalid short URL' => [
new Uri('/foo'), new Uri('/foo'),
$this->notFoundType($this->requestForRoute(RedirectAction::class)), self::notFoundType(self::requestForRoute(RedirectAction::class)),
new NotFoundRedirectOptions(invalidShortUrl: 'invalidShortUrl'), new NotFoundRedirectOptions(invalidShortUrl: 'invalidShortUrl'),
'invalidShortUrl', 'invalidShortUrl',
]; ];
yield 'invalid short URL with path placeholder' => [ yield 'invalid short URL with path placeholder' => [
new Uri('/foo'), new Uri('/foo'),
$this->notFoundType($this->requestForRoute(RedirectAction::class)), self::notFoundType(self::requestForRoute(RedirectAction::class)),
new NotFoundRedirectOptions(invalidShortUrl: 'https://redirect-here.com/{ORIGINAL_PATH}'), new NotFoundRedirectOptions(invalidShortUrl: 'https://redirect-here.com/{ORIGINAL_PATH}'),
'https://redirect-here.com/foo', 'https://redirect-here.com/foo',
]; ];
} }
/** @test */ #[Test]
public function noResponseIsReturnedIfNoConditionsMatch(): void public function noResponseIsReturnedIfNoConditionsMatch(): void
{ {
$notFoundType = $this->notFoundType($this->requestForRoute('foo')); $notFoundType = self::notFoundType(self::requestForRoute('foo'));
$this->helper->expects($this->never())->method('buildRedirectResponse'); $this->helper->expects($this->never())->method('buildRedirectResponse');
$result = $this->resolver->resolveRedirectResponse($notFoundType, new NotFoundRedirectOptions(), new Uri()); $result = $this->resolver->resolveRedirectResponse($notFoundType, new NotFoundRedirectOptions(), new Uri());
@ -123,12 +123,12 @@ class NotFoundRedirectResolverTest extends TestCase
self::assertNull($result); self::assertNull($result);
} }
private function notFoundType(ServerRequestInterface $req): NotFoundType private static function notFoundType(ServerRequestInterface $req): NotFoundType
{ {
return NotFoundType::fromRequest($req, ''); return NotFoundType::fromRequest($req, '');
} }
private function requestForRoute(string $routeName): ServerRequestInterface private static function requestForRoute(string $routeName): ServerRequestInterface
{ {
return ServerRequestFactory::fromGlobals() return ServerRequestFactory::fromGlobals()
->withAttribute( ->withAttribute(
@ -136,7 +136,8 @@ class NotFoundRedirectResolverTest extends TestCase
RouteResult::fromRoute( RouteResult::fromRoute(
new Route( new Route(
'foo', 'foo',
$this->createMock(MiddlewareInterface::class), middleware(function (): void {
}),
['GET'], ['GET'],
$routeName, $routeName,
), ),

View File

@ -4,6 +4,8 @@ declare(strict_types=1);
namespace ShlinkioTest\Shlink\Core\Config\PostProcessor; namespace ShlinkioTest\Shlink\Core\Config\PostProcessor;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Shlinkio\Shlink\Core\Config\PostProcessor\BasePathPrefixer; use Shlinkio\Shlink\Core\Config\PostProcessor\BasePathPrefixer;
@ -16,10 +18,7 @@ class BasePathPrefixerTest extends TestCase
$this->prefixer = new BasePathPrefixer(); $this->prefixer = new BasePathPrefixer();
} }
/** #[Test, DataProvider('provideConfig')]
* @test
* @dataProvider provideConfig
*/
public function parsesConfigAsExpected( public function parsesConfigAsExpected(
array $originalConfig, array $originalConfig,
array $expectedRoutes, array $expectedRoutes,
@ -31,7 +30,7 @@ class BasePathPrefixerTest extends TestCase
self::assertEquals($expectedMiddlewares, $middlewares); self::assertEquals($expectedMiddlewares, $middlewares);
} }
public function provideConfig(): iterable public static function provideConfig(): iterable
{ {
yield 'with empty options' => [['routes' => []], [], []]; yield 'with empty options' => [['routes' => []], [], []];
yield 'with non-empty options' => [ yield 'with non-empty options' => [

View File

@ -4,6 +4,8 @@ declare(strict_types=1);
namespace ShlinkioTest\Shlink\Core\Config\PostProcessor; namespace ShlinkioTest\Shlink\Core\Config\PostProcessor;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Shlinkio\Shlink\Core\Config\PostProcessor\MultiSegmentSlugProcessor; use Shlinkio\Shlink\Core\Config\PostProcessor\MultiSegmentSlugProcessor;
@ -16,16 +18,13 @@ class MultiSegmentSlugProcessorTest extends TestCase
$this->processor = new MultiSegmentSlugProcessor(); $this->processor = new MultiSegmentSlugProcessor();
} }
/** #[Test, DataProvider('provideConfigs')]
* @test
* @dataProvider provideConfigs
*/
public function parsesRoutesAsExpected(array $config, array $expectedRoutes): void public function parsesRoutesAsExpected(array $config, array $expectedRoutes): void
{ {
self::assertEquals($expectedRoutes, ($this->processor)($config)['routes'] ?? []); self::assertEquals($expectedRoutes, ($this->processor)($config)['routes'] ?? []);
} }
public function provideConfigs(): iterable public static function provideConfigs(): iterable
{ {
yield [[], []]; yield [[], []];
yield [['url_shortener' => []], []]; yield [['url_shortener' => []], []];

View File

@ -5,6 +5,8 @@ declare(strict_types=1);
namespace ShlinkioTest\Shlink\Core\Config\PostProcessor; namespace ShlinkioTest\Shlink\Core\Config\PostProcessor;
use Mezzio\Router\Route; use Mezzio\Router\Route;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Shlinkio\Shlink\Core\Action\RedirectAction; use Shlinkio\Shlink\Core\Action\RedirectAction;
use Shlinkio\Shlink\Core\Config\PostProcessor\ShortUrlMethodsProcessor; use Shlinkio\Shlink\Core\Config\PostProcessor\ShortUrlMethodsProcessor;
@ -18,10 +20,7 @@ class ShortUrlMethodsProcessorTest extends TestCase
$this->processor = new ShortUrlMethodsProcessor(); $this->processor = new ShortUrlMethodsProcessor();
} }
/** #[Test, DataProvider('provideConfigs')]
* @test
* @dataProvider provideConfigs
*/
public function onlyFirstRouteIdentifiedAsRedirectIsEditedWithProperAllowedMethods( public function onlyFirstRouteIdentifiedAsRedirectIsEditedWithProperAllowedMethods(
array $config, array $config,
?array $expectedRoutes, ?array $expectedRoutes,
@ -29,7 +28,7 @@ class ShortUrlMethodsProcessorTest extends TestCase
self::assertEquals($expectedRoutes, ($this->processor)($config)['routes'] ?? null); self::assertEquals($expectedRoutes, ($this->processor)($config)['routes'] ?? null);
} }
public function provideConfigs(): iterable public static function provideConfigs(): iterable
{ {
$buildConfigWithStatus = static fn (int $status, ?array $expectedAllowedMethods) => [[ $buildConfigWithStatus = static fn (int $status, ?array $expectedAllowedMethods) => [[
'routes' => [ 'routes' => [

View File

@ -5,6 +5,7 @@ declare(strict_types=1);
namespace ShlinkioTest\Shlink\Core; namespace ShlinkioTest\Shlink\Core;
use Laminas\ServiceManager\AbstractFactory\ConfigAbstractFactory; use Laminas\ServiceManager\AbstractFactory\ConfigAbstractFactory;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Shlinkio\Shlink\Core\ConfigProvider; use Shlinkio\Shlink\Core\ConfigProvider;
@ -17,7 +18,7 @@ class ConfigProviderTest extends TestCase
$this->configProvider = new ConfigProvider(); $this->configProvider = new ConfigProvider();
} }
/** @test */ #[Test]
public function properConfigIsReturned(): void public function properConfigIsReturned(): void
{ {
$config = ($this->configProvider)(); $config = ($this->configProvider)();

View File

@ -4,6 +4,7 @@ declare(strict_types=1);
namespace ShlinkioTest\Shlink\Core\Crawling; namespace ShlinkioTest\Shlink\Core\Crawling;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Shlinkio\Shlink\Core\Crawling\CrawlingHelper; use Shlinkio\Shlink\Core\Crawling\CrawlingHelper;
@ -20,7 +21,7 @@ class CrawlingHelperTest extends TestCase
$this->helper = new CrawlingHelper($this->query); $this->helper = new CrawlingHelper($this->query);
} }
/** @test */ #[Test]
public function listCrawlableShortCodesDelegatesIntoRepository(): void public function listCrawlableShortCodesDelegatesIntoRepository(): void
{ {
$this->query->expects($this->once())->method('__invoke')->willReturn([]); $this->query->expects($this->once())->method('__invoke')->willReturn([]);

View File

@ -5,6 +5,8 @@ declare(strict_types=1);
namespace ShlinkioTest\Shlink\Core\Domain; namespace ShlinkioTest\Shlink\Core\Domain;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Shlinkio\Shlink\Core\Config\EmptyNotFoundRedirectConfig; use Shlinkio\Shlink\Core\Config\EmptyNotFoundRedirectConfig;
@ -29,10 +31,7 @@ class DomainServiceTest extends TestCase
$this->domainService = new DomainService($this->em, 'default.com'); $this->domainService = new DomainService($this->em, 'default.com');
} }
/** #[Test, DataProvider('provideExcludedDomains')]
* @test
* @dataProvider provideExcludedDomains
*/
public function listDomainsDelegatesIntoRepository(array $domains, array $expectedResult, ?ApiKey $apiKey): void public function listDomainsDelegatesIntoRepository(array $domains, array $expectedResult, ?ApiKey $apiKey): void
{ {
$repo = $this->createMock(DomainRepositoryInterface::class); $repo = $this->createMock(DomainRepositoryInterface::class);
@ -44,7 +43,7 @@ class DomainServiceTest extends TestCase
self::assertEquals($expectedResult, $result); self::assertEquals($expectedResult, $result);
} }
public function provideExcludedDomains(): iterable public static function provideExcludedDomains(): iterable
{ {
$default = DomainItem::forDefaultDomain('default.com', new EmptyNotFoundRedirectConfig()); $default = DomainItem::forDefaultDomain('default.com', new EmptyNotFoundRedirectConfig());
$adminApiKey = ApiKey::create(); $adminApiKey = ApiKey::create();
@ -102,7 +101,7 @@ class DomainServiceTest extends TestCase
]; ];
} }
/** @test */ #[Test]
public function getDomainThrowsExceptionWhenDomainIsNotFound(): void public function getDomainThrowsExceptionWhenDomainIsNotFound(): void
{ {
$this->em->expects($this->once())->method('find')->with(Domain::class, '123')->willReturn(null); $this->em->expects($this->once())->method('find')->with(Domain::class, '123')->willReturn(null);
@ -112,7 +111,7 @@ class DomainServiceTest extends TestCase
$this->domainService->getDomain('123'); $this->domainService->getDomain('123');
} }
/** @test */ #[Test]
public function getDomainReturnsEntityWhenFound(): void public function getDomainReturnsEntityWhenFound(): void
{ {
$domain = Domain::withAuthority(''); $domain = Domain::withAuthority('');
@ -123,10 +122,7 @@ class DomainServiceTest extends TestCase
self::assertSame($domain, $result); self::assertSame($domain, $result);
} }
/** #[Test, DataProvider('provideFoundDomains')]
* @test
* @dataProvider provideFoundDomains
*/
public function getOrCreateAlwaysPersistsDomain(?Domain $foundDomain, ?ApiKey $apiKey): void public function getOrCreateAlwaysPersistsDomain(?Domain $foundDomain, ?ApiKey $apiKey): void
{ {
$authority = 'example.com'; $authority = 'example.com';
@ -145,7 +141,7 @@ class DomainServiceTest extends TestCase
} }
} }
/** @test */ #[Test]
public function getOrCreateThrowsExceptionForApiKeysWithDomainRole(): void public function getOrCreateThrowsExceptionForApiKeysWithDomainRole(): void
{ {
$authority = 'example.com'; $authority = 'example.com';
@ -163,10 +159,7 @@ class DomainServiceTest extends TestCase
$this->domainService->getOrCreate($authority, $apiKey); $this->domainService->getOrCreate($authority, $apiKey);
} }
/** #[Test, DataProvider('provideFoundDomains')]
* @test
* @dataProvider provideFoundDomains
*/
public function configureNotFoundRedirectsConfiguresFetchedDomain(?Domain $foundDomain, ?ApiKey $apiKey): void public function configureNotFoundRedirectsConfiguresFetchedDomain(?Domain $foundDomain, ?ApiKey $apiKey): void
{ {
$authority = 'example.com'; $authority = 'example.com';
@ -190,7 +183,7 @@ class DomainServiceTest extends TestCase
self::assertEquals('baz.com', $result->invalidShortUrlRedirect()); self::assertEquals('baz.com', $result->invalidShortUrlRedirect());
} }
public function provideFoundDomains(): iterable public static function provideFoundDomains(): iterable
{ {
$domain = Domain::withAuthority(''); $domain = Domain::withAuthority('');
$adminApiKey = ApiKey::create(); $adminApiKey = ApiKey::create();

View File

@ -6,6 +6,9 @@ namespace ShlinkioTest\Shlink\Core\ErrorHandler;
use Laminas\Diactoros\Response; use Laminas\Diactoros\Response;
use Laminas\Diactoros\ServerRequestFactory; use Laminas\Diactoros\ServerRequestFactory;
use PHPUnit\Framework\Assert;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ServerRequestInterface;
@ -42,10 +45,7 @@ class NotFoundRedirectHandlerTest extends TestCase
); );
} }
/** #[Test, DataProvider('provideNonRedirectScenarios')]
* @test
* @dataProvider provideNonRedirectScenarios
*/
public function nextIsCalledWhenNoRedirectIsResolved(callable $setUp): void public function nextIsCalledWhenNoRedirectIsResolved(callable $setUp): void
{ {
$expectedResp = new Response(); $expectedResp = new Response();
@ -58,44 +58,43 @@ class NotFoundRedirectHandlerTest extends TestCase
self::assertSame($expectedResp, $result); self::assertSame($expectedResp, $result);
} }
public function provideNonRedirectScenarios(): iterable public static function provideNonRedirectScenarios(): iterable
{ {
yield 'no domain' => [function ( yield 'no domain' => [function (
MockObject&DomainServiceInterface $domainService, MockObject&DomainServiceInterface $domainService,
MockObject&NotFoundRedirectResolverInterface $resolver, MockObject&NotFoundRedirectResolverInterface $resolver,
): void { ): void {
$domainService->expects($this->once())->method('findByAuthority')->withAnyParameters()->willReturn( $domainService->expects(self::once())->method('findByAuthority')->withAnyParameters()->willReturn(
null, null,
); );
$resolver->expects($this->once())->method('resolveRedirectResponse')->with( $resolver->expects(self::once())->method('resolveRedirectResponse')->with(
$this->isInstanceOf(NotFoundType::class), self::isInstanceOf(NotFoundType::class),
$this->isInstanceOf(NotFoundRedirectOptions::class), self::isInstanceOf(NotFoundRedirectOptions::class),
$this->isInstanceOf(UriInterface::class), self::isInstanceOf(UriInterface::class),
)->willReturn(null); )->willReturn(null);
}]; }];
yield 'non-redirecting domain' => [function ( yield 'non-redirecting domain' => [function (
MockObject&DomainServiceInterface $domainService, MockObject&DomainServiceInterface $domainService,
MockObject&NotFoundRedirectResolverInterface $resolver, MockObject&NotFoundRedirectResolverInterface $resolver,
): void { ): void {
$domainService->expects($this->once())->method('findByAuthority')->withAnyParameters()->willReturn( $domainService->expects(self::once())->method('findByAuthority')->withAnyParameters()->willReturn(
Domain::withAuthority(''), Domain::withAuthority(''),
); );
$resolver->expects($this->exactly(2))->method('resolveRedirectResponse')->withConsecutive( $callCount = 0;
[ $resolver->expects(self::exactly(2))->method('resolveRedirectResponse')->willReturnCallback(
$this->isInstanceOf(NotFoundType::class), function (mixed $arg1, mixed $arg2, mixed $arg3) use (&$callCount) {
$this->isInstanceOf(Domain::class), Assert::assertInstanceOf(NotFoundType::class, $arg1);
$this->isInstanceOf(UriInterface::class), Assert::assertInstanceOf($callCount === 0 ? Domain::class : NotFoundRedirectOptions::class, $arg2);
], Assert::assertInstanceOf(UriInterface::class, $arg3);
[
$this->isInstanceOf(NotFoundType::class), $callCount++;
$this->isInstanceOf(NotFoundRedirectOptions::class), return null;
$this->isInstanceOf(UriInterface::class), },
], );
)->willReturn(null);
}]; }];
} }
/** @test */ #[Test]
public function globalRedirectIsUsedIfDomainRedirectIsNotFound(): void public function globalRedirectIsUsedIfDomainRedirectIsNotFound(): void
{ {
$expectedResp = new Response(); $expectedResp = new Response();
@ -113,7 +112,7 @@ class NotFoundRedirectHandlerTest extends TestCase
self::assertSame($expectedResp, $result); self::assertSame($expectedResp, $result);
} }
/** @test */ #[Test]
public function domainRedirectIsUsedIfFound(): void public function domainRedirectIsUsedIfFound(): void
{ {
$expectedResp = new Response(); $expectedResp = new Response();

View File

@ -9,13 +9,16 @@ use Laminas\Diactoros\ServerRequestFactory;
use Laminas\Diactoros\Uri; use Laminas\Diactoros\Uri;
use Mezzio\Router\Route; use Mezzio\Router\Route;
use Mezzio\Router\RouteResult; use Mezzio\Router\RouteResult;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Shlinkio\Shlink\Core\Action\RedirectAction; use Shlinkio\Shlink\Core\Action\RedirectAction;
use Shlinkio\Shlink\Core\ErrorHandler\Model\NotFoundType; use Shlinkio\Shlink\Core\ErrorHandler\Model\NotFoundType;
use Shlinkio\Shlink\Core\ErrorHandler\NotFoundTemplateHandler; use Shlinkio\Shlink\Core\ErrorHandler\NotFoundTemplateHandler;
use function Laminas\Stratigility\middleware;
class NotFoundTemplateHandlerTest extends TestCase class NotFoundTemplateHandlerTest extends TestCase
{ {
private NotFoundTemplateHandler $handler; private NotFoundTemplateHandler $handler;
@ -31,10 +34,7 @@ class NotFoundTemplateHandlerTest extends TestCase
$this->handler = new NotFoundTemplateHandler($readFile); $this->handler = new NotFoundTemplateHandler($readFile);
} }
/** #[Test, DataProvider('provideTemplates')]
* @test
* @dataProvider provideTemplates
*/
public function properErrorTemplateIsRendered(ServerRequestInterface $request, string $expectedTemplate): void public function properErrorTemplateIsRendered(ServerRequestInterface $request, string $expectedTemplate): void
{ {
$resp = $this->handler->handle($request->withHeader('Accept', 'text/html')); $resp = $this->handler->handle($request->withHeader('Accept', 'text/html'));
@ -44,19 +44,20 @@ class NotFoundTemplateHandlerTest extends TestCase
self::assertTrue($this->readFileCalled); self::assertTrue($this->readFileCalled);
} }
public function provideTemplates(): iterable public static function provideTemplates(): iterable
{ {
$request = ServerRequestFactory::fromGlobals()->withUri(new Uri('/foo')); $request = ServerRequestFactory::fromGlobals()->withUri(new Uri('/foo'));
yield 'base url' => [$this->withNotFoundType($request, '/foo'), NotFoundTemplateHandler::NOT_FOUND_TEMPLATE]; yield 'base url' => [self::withNotFoundType($request, '/foo'), NotFoundTemplateHandler::NOT_FOUND_TEMPLATE];
yield 'regular not found' => [$this->withNotFoundType($request), NotFoundTemplateHandler::NOT_FOUND_TEMPLATE]; yield 'regular not found' => [self::withNotFoundType($request), NotFoundTemplateHandler::NOT_FOUND_TEMPLATE];
yield 'invalid short code' => [ yield 'invalid short code' => [
$this->withNotFoundType($request->withAttribute( self::withNotFoundType($request->withAttribute(
RouteResult::class, RouteResult::class,
RouteResult::fromRoute( RouteResult::fromRoute(
new Route( new Route(
'foo', 'foo',
$this->createMock(MiddlewareInterface::class), middleware(function (): void {
}),
['GET'], ['GET'],
RedirectAction::class, RedirectAction::class,
), ),
@ -66,7 +67,7 @@ class NotFoundTemplateHandlerTest extends TestCase
]; ];
} }
private function withNotFoundType(ServerRequestInterface $req, string $baseUrl = ''): ServerRequestInterface private static function withNotFoundType(ServerRequestInterface $req, string $baseUrl = ''): ServerRequestInterface
{ {
$type = NotFoundType::fromRequest($req, $baseUrl); $type = NotFoundType::fromRequest($req, $baseUrl);
return $req->withAttribute(NotFoundType::class, $type); return $req->withAttribute(NotFoundType::class, $type);

View File

@ -5,6 +5,7 @@ declare(strict_types=1);
namespace ShlinkioTest\Shlink\Core\ErrorHandler; namespace ShlinkioTest\Shlink\Core\ErrorHandler;
use Laminas\Diactoros\ServerRequestFactory; use Laminas\Diactoros\ServerRequestFactory;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ServerRequestInterface;
@ -32,7 +33,7 @@ class NotFoundTrackerMiddlewareTest extends TestCase
); );
} }
/** @test */ #[Test]
public function delegatesIntoRequestTracker(): void public function delegatesIntoRequestTracker(): void
{ {
$this->handler->expects($this->once())->method('handle')->with($this->request); $this->handler->expects($this->once())->method('handle')->with($this->request);

View File

@ -7,6 +7,7 @@ namespace ShlinkioTest\Shlink\Core\ErrorHandler;
use Laminas\Diactoros\Response; use Laminas\Diactoros\Response;
use Laminas\Diactoros\ServerRequestFactory; use Laminas\Diactoros\ServerRequestFactory;
use PHPUnit\Framework\Assert; use PHPUnit\Framework\Assert;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ServerRequestInterface;
@ -25,7 +26,7 @@ class NotFoundTypeResolverMiddlewareTest extends TestCase
$this->handler = $this->createMock(RequestHandlerInterface::class); $this->handler = $this->createMock(RequestHandlerInterface::class);
} }
/** @test */ #[Test]
public function notFoundTypeIsAddedToRequest(): void public function notFoundTypeIsAddedToRequest(): void
{ {
$request = ServerRequestFactory::fromGlobals(); $request = ServerRequestFactory::fromGlobals();

View File

@ -4,6 +4,7 @@ declare(strict_types=1);
namespace ShlinkioTest\Shlink\Core\EventDispatcher; namespace ShlinkioTest\Shlink\Core\EventDispatcher;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Psr\Container\ContainerInterface; use Psr\Container\ContainerInterface;
@ -21,7 +22,7 @@ class CloseDbConnectionEventListenerDelegatorTest extends TestCase
$this->delegator = new CloseDbConnectionEventListenerDelegator(); $this->delegator = new CloseDbConnectionEventListenerDelegator();
} }
/** @test */ #[Test]
public function properDependenciesArePassed(): void public function properDependenciesArePassed(): void
{ {
$callbackInvoked = false; $callbackInvoked = false;

View File

@ -5,6 +5,8 @@ declare(strict_types=1);
namespace ShlinkioTest\Shlink\Core\EventDispatcher; namespace ShlinkioTest\Shlink\Core\EventDispatcher;
use Doctrine\DBAL\Connection; use Doctrine\DBAL\Connection;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use RuntimeException; use RuntimeException;
@ -22,10 +24,7 @@ class CloseDbConnectionEventListenerTest extends TestCase
$this->em = $this->createMock(ReopeningEntityManagerInterface::class); $this->em = $this->createMock(ReopeningEntityManagerInterface::class);
} }
/** #[Test, DataProvider('provideWrapped')]
* @test
* @dataProvider provideWrapped
*/
public function connectionIsOpenedBeforeAndClosedAfter(callable $wrapped, bool &$wrappedWasCalled): void public function connectionIsOpenedBeforeAndClosedAfter(callable $wrapped, bool &$wrappedWasCalled): void
{ {
$conn = $this->createMock(Connection::class); $conn = $this->createMock(Connection::class);
@ -46,7 +45,7 @@ class CloseDbConnectionEventListenerTest extends TestCase
self::assertTrue($wrappedWasCalled); self::assertTrue($wrappedWasCalled);
} }
public function provideWrapped(): iterable public static function provideWrapped(): iterable
{ {
yield 'does not throw exception' => (static function (): array { yield 'does not throw exception' => (static function (): array {
$wrappedWasCalled = false; $wrappedWasCalled = false;

View File

@ -4,6 +4,7 @@ declare(strict_types=1);
namespace ShlinkioTest\Shlink\Core\EventDispatcher; namespace ShlinkioTest\Shlink\Core\EventDispatcher;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Shlinkio\Shlink\Core\EventDispatcher\Event\GeoLiteDbCreated; use Shlinkio\Shlink\Core\EventDispatcher\Event\GeoLiteDbCreated;
@ -28,14 +29,14 @@ class LocateUnlocatedVisitsTest extends TestCase
$this->listener = new LocateUnlocatedVisits($this->locator, $this->visitToLocation); $this->listener = new LocateUnlocatedVisits($this->locator, $this->visitToLocation);
} }
/** @test */ #[Test]
public function locatorIsCalledWhenInvoked(): void public function locatorIsCalledWhenInvoked(): void
{ {
$this->locator->expects($this->once())->method('locateUnlocatedVisits')->with($this->listener); $this->locator->expects($this->once())->method('locateUnlocatedVisits')->with($this->listener);
($this->listener)(new GeoLiteDbCreated()); ($this->listener)(new GeoLiteDbCreated());
} }
/** @test */ #[Test]
public function visitToLocationHelperIsCalledToGeolocateVisits(): void public function visitToLocationHelperIsCalledToGeolocateVisits(): void
{ {
$visit = Visit::forBasePath(Visitor::emptyInstance()); $visit = Visit::forBasePath(Visitor::emptyInstance());

View File

@ -6,6 +6,8 @@ namespace ShlinkioTest\Shlink\Core\EventDispatcher;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use OutOfRangeException; use OutOfRangeException;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Psr\EventDispatcher\EventDispatcherInterface; use Psr\EventDispatcher\EventDispatcherInterface;
@ -49,7 +51,7 @@ class LocateVisitTest extends TestCase
); );
} }
/** @test */ #[Test]
public function invalidVisitLogsWarning(): void public function invalidVisitLogsWarning(): void
{ {
$event = new UrlVisited('123'); $event = new UrlVisited('123');
@ -65,7 +67,7 @@ class LocateVisitTest extends TestCase
($this->locateVisit)($event); ($this->locateVisit)($event);
} }
/** @test */ #[Test]
public function nonExistingGeoLiteDbLogsWarning(): void public function nonExistingGeoLiteDbLogsWarning(): void
{ {
$event = new UrlVisited('123'); $event = new UrlVisited('123');
@ -84,7 +86,7 @@ class LocateVisitTest extends TestCase
($this->locateVisit)($event); ($this->locateVisit)($event);
} }
/** @test */ #[Test]
public function invalidAddressLogsWarning(): void public function invalidAddressLogsWarning(): void
{ {
$event = new UrlVisited('123'); $event = new UrlVisited('123');
@ -105,7 +107,7 @@ class LocateVisitTest extends TestCase
($this->locateVisit)($event); ($this->locateVisit)($event);
} }
/** @test */ #[Test]
public function unhandledExceptionLogsError(): void public function unhandledExceptionLogsError(): void
{ {
$event = new UrlVisited('123'); $event = new UrlVisited('123');
@ -126,10 +128,7 @@ class LocateVisitTest extends TestCase
($this->locateVisit)($event); ($this->locateVisit)($event);
} }
/** #[Test, DataProvider('provideNonLocatableVisits')]
* @test
* @dataProvider provideNonLocatableVisits
*/
public function nonLocatableVisitsResolveToEmptyLocations(Visit $visit): void public function nonLocatableVisitsResolveToEmptyLocations(Visit $visit): void
{ {
$event = new UrlVisited('123'); $event = new UrlVisited('123');
@ -146,7 +145,7 @@ class LocateVisitTest extends TestCase
self::assertEquals($visit->getVisitLocation(), VisitLocation::fromGeolocation(Location::emptyInstance())); self::assertEquals($visit->getVisitLocation(), VisitLocation::fromGeolocation(Location::emptyInstance()));
} }
public function provideNonLocatableVisits(): iterable public static function provideNonLocatableVisits(): iterable
{ {
$shortUrl = ShortUrl::createFake(); $shortUrl = ShortUrl::createFake();
@ -155,10 +154,7 @@ class LocateVisitTest extends TestCase
yield 'localhost' => [Visit::forValidShortUrl($shortUrl, new Visitor('', '', IpAddress::LOCALHOST, ''))]; yield 'localhost' => [Visit::forValidShortUrl($shortUrl, new Visitor('', '', IpAddress::LOCALHOST, ''))];
} }
/** #[Test, DataProvider('provideIpAddresses')]
* @test
* @dataProvider provideIpAddresses
*/
public function locatableVisitsResolveToLocation(Visit $visit, ?string $originalIpAddress): void public function locatableVisitsResolveToLocation(Visit $visit, ?string $originalIpAddress): void
{ {
$ipAddr = $originalIpAddress ?? $visit->getRemoteAddr(); $ipAddr = $originalIpAddress ?? $visit->getRemoteAddr();
@ -180,7 +176,7 @@ class LocateVisitTest extends TestCase
self::assertEquals($visit->getVisitLocation(), VisitLocation::fromGeolocation($location)); self::assertEquals($visit->getVisitLocation(), VisitLocation::fromGeolocation($location));
} }
public function provideIpAddresses(): iterable public static function provideIpAddresses(): iterable
{ {
yield 'no original IP address' => [ yield 'no original IP address' => [
Visit::forValidShortUrl(ShortUrl::createFake(), new Visitor('', '', '1.2.3.4', '')), Visit::forValidShortUrl(ShortUrl::createFake(), new Visitor('', '', '1.2.3.4', '')),

View File

@ -6,6 +6,7 @@ namespace ShlinkioTest\Shlink\Core\EventDispatcher\Mercure;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use Exception; use Exception;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
@ -39,7 +40,7 @@ class NotifyNewShortUrlToMercureTest extends TestCase
); );
} }
/** @test */ #[Test]
public function messageIsLoggedWhenShortUrlIsNotFound(): void public function messageIsLoggedWhenShortUrlIsNotFound(): void
{ {
$this->em->expects($this->once())->method('find')->with(ShortUrl::class, '123')->willReturn(null); $this->em->expects($this->once())->method('find')->with(ShortUrl::class, '123')->willReturn(null);
@ -54,7 +55,7 @@ class NotifyNewShortUrlToMercureTest extends TestCase
($this->listener)(new ShortUrlCreated('123')); ($this->listener)(new ShortUrlCreated('123'));
} }
/** @test */ #[Test]
public function expectedNotificationIsPublished(): void public function expectedNotificationIsPublished(): void
{ {
$shortUrl = ShortUrl::withLongUrl('longUrl'); $shortUrl = ShortUrl::withLongUrl('longUrl');
@ -71,7 +72,7 @@ class NotifyNewShortUrlToMercureTest extends TestCase
($this->listener)(new ShortUrlCreated('123')); ($this->listener)(new ShortUrlCreated('123'));
} }
/** @test */ #[Test]
public function messageIsPrintedIfPublishingFails(): void public function messageIsPrintedIfPublishingFails(): void
{ {
$shortUrl = ShortUrl::withLongUrl('longUrl'); $shortUrl = ShortUrl::withLongUrl('longUrl');

View File

@ -5,6 +5,8 @@ declare(strict_types=1);
namespace ShlinkioTest\Shlink\Core\EventDispatcher\Mercure; namespace ShlinkioTest\Shlink\Core\EventDispatcher\Mercure;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
@ -37,7 +39,7 @@ class NotifyVisitToMercureTest extends TestCase
$this->listener = new NotifyVisitToMercure($this->helper, $this->updatesGenerator, $this->em, $this->logger); $this->listener = new NotifyVisitToMercure($this->helper, $this->updatesGenerator, $this->em, $this->logger);
} }
/** @test */ #[Test]
public function notificationsAreNotSentWhenVisitCannotBeFound(): void public function notificationsAreNotSentWhenVisitCannotBeFound(): void
{ {
$visitId = '123'; $visitId = '123';
@ -55,7 +57,7 @@ class NotifyVisitToMercureTest extends TestCase
($this->listener)(new VisitLocated($visitId)); ($this->listener)(new VisitLocated($visitId));
} }
/** @test */ #[Test]
public function notificationsAreSentWhenVisitIsFound(): void public function notificationsAreSentWhenVisitIsFound(): void
{ {
$visitId = '123'; $visitId = '123';
@ -75,7 +77,7 @@ class NotifyVisitToMercureTest extends TestCase
($this->listener)(new VisitLocated($visitId)); ($this->listener)(new VisitLocated($visitId));
} }
/** @test */ #[Test]
public function debugIsLoggedWhenExceptionIsThrown(): void public function debugIsLoggedWhenExceptionIsThrown(): void
{ {
$visitId = '123'; $visitId = '123';
@ -99,10 +101,7 @@ class NotifyVisitToMercureTest extends TestCase
($this->listener)(new VisitLocated($visitId)); ($this->listener)(new VisitLocated($visitId));
} }
/** #[Test, DataProvider('provideOrphanVisits')]
* @test
* @dataProvider provideOrphanVisits
*/
public function notificationsAreSentForOrphanVisits(Visit $visit): void public function notificationsAreSentForOrphanVisits(Visit $visit): void
{ {
$visitId = '123'; $visitId = '123';
@ -121,7 +120,7 @@ class NotifyVisitToMercureTest extends TestCase
($this->listener)(new VisitLocated($visitId)); ($this->listener)(new VisitLocated($visitId));
} }
public function provideOrphanVisits(): iterable public static function provideOrphanVisits(): iterable
{ {
$visitor = Visitor::emptyInstance(); $visitor = Visitor::emptyInstance();

View File

@ -12,6 +12,8 @@ use GuzzleHttp\Promise\FulfilledPromise;
use GuzzleHttp\Promise\RejectedPromise; use GuzzleHttp\Promise\RejectedPromise;
use GuzzleHttp\RequestOptions; use GuzzleHttp\RequestOptions;
use PHPUnit\Framework\Assert; use PHPUnit\Framework\Assert;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
@ -41,7 +43,7 @@ class NotifyVisitToWebHooksTest extends TestCase
$this->logger = $this->createMock(LoggerInterface::class); $this->logger = $this->createMock(LoggerInterface::class);
} }
/** @test */ #[Test]
public function emptyWebhooksMakeNoFurtherActions(): void public function emptyWebhooksMakeNoFurtherActions(): void
{ {
$this->em->expects($this->never())->method('find'); $this->em->expects($this->never())->method('find');
@ -49,7 +51,7 @@ class NotifyVisitToWebHooksTest extends TestCase
$this->createListener([])(new VisitLocated('1')); $this->createListener([])(new VisitLocated('1'));
} }
/** @test */ #[Test]
public function invalidVisitDoesNotPerformAnyRequest(): void public function invalidVisitDoesNotPerformAnyRequest(): void
{ {
$this->em->expects($this->once())->method('find')->with(Visit::class, '1')->willReturn(null); $this->em->expects($this->once())->method('find')->with(Visit::class, '1')->willReturn(null);
@ -62,7 +64,7 @@ class NotifyVisitToWebHooksTest extends TestCase
$this->createListener(['foo', 'bar'])(new VisitLocated('1')); $this->createListener(['foo', 'bar'])(new VisitLocated('1'));
} }
/** @test */ #[Test]
public function orphanVisitDoesNotPerformAnyRequestWhenDisabled(): void public function orphanVisitDoesNotPerformAnyRequestWhenDisabled(): void
{ {
$this->em->expects($this->once())->method('find')->with(Visit::class, '1')->willReturn( $this->em->expects($this->once())->method('find')->with(Visit::class, '1')->willReturn(
@ -74,10 +76,7 @@ class NotifyVisitToWebHooksTest extends TestCase
$this->createListener(['foo', 'bar'], false)(new VisitLocated('1')); $this->createListener(['foo', 'bar'], false)(new VisitLocated('1'));
} }
/** #[Test, DataProvider('provideVisits')]
* @test
* @dataProvider provideVisits
*/
public function expectedRequestsArePerformedToWebhooks(Visit $visit, array $expectedResponseKeys): void public function expectedRequestsArePerformedToWebhooks(Visit $visit, array $expectedResponseKeys): void
{ {
$webhooks = ['foo', 'invalid', 'bar', 'baz']; $webhooks = ['foo', 'invalid', 'bar', 'baz'];
@ -120,13 +119,13 @@ class NotifyVisitToWebHooksTest extends TestCase
$this->createListener($webhooks)(new VisitLocated('1')); $this->createListener($webhooks)(new VisitLocated('1'));
} }
public function provideVisits(): iterable public static function provideVisits(): iterable
{ {
yield 'regular visit' => [ yield 'regular visit' => [
Visit::forValidShortUrl(ShortUrl::createFake(), Visitor::emptyInstance()), Visit::forValidShortUrl(ShortUrl::createFake(), Visitor::emptyInstance()),
['shortUrl', 'visit'], ['shortUrl', 'visit'],
]; ];
yield 'orphan visit' => [Visit::forBasePath(Visitor::emptyInstance()), ['visit'],]; yield 'orphan visit' => [Visit::forBasePath(Visitor::emptyInstance()), ['visit']];
} }
private function createListener(array $webhooks, bool $notifyOrphanVisits = true): NotifyVisitToWebHooks private function createListener(array $webhooks, bool $notifyOrphanVisits = true): NotifyVisitToWebHooks

View File

@ -4,6 +4,8 @@ declare(strict_types=1);
namespace ShlinkioTest\Shlink\Core\EventDispatcher; namespace ShlinkioTest\Shlink\Core\EventDispatcher;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Shlinkio\Shlink\Common\UpdatePublishing\Update; use Shlinkio\Shlink\Common\UpdatePublishing\Update;
use Shlinkio\Shlink\Core\EventDispatcher\PublishingUpdatesGenerator; use Shlinkio\Shlink\Core\EventDispatcher\PublishingUpdatesGenerator;
@ -30,10 +32,7 @@ class PublishingUpdatesGeneratorTest extends TestCase
); );
} }
/** #[Test, DataProvider('provideMethod')]
* @test
* @dataProvider provideMethod
*/
public function visitIsProperlySerializedIntoUpdate(string $method, string $expectedTopic, ?string $title): void public function visitIsProperlySerializedIntoUpdate(string $method, string $expectedTopic, ?string $title): void
{ {
$shortUrl = ShortUrl::create(ShortUrlCreation::fromRawData([ $shortUrl = ShortUrl::create(ShortUrlCreation::fromRawData([
@ -77,16 +76,13 @@ class PublishingUpdatesGeneratorTest extends TestCase
], $update->payload); ], $update->payload);
} }
public function provideMethod(): iterable public static function provideMethod(): iterable
{ {
yield 'newVisitUpdate' => ['newVisitUpdate', 'https://shlink.io/new-visit', 'the cool title']; yield 'newVisitUpdate' => ['newVisitUpdate', 'https://shlink.io/new-visit', 'the cool title'];
yield 'newShortUrlVisitUpdate' => ['newShortUrlVisitUpdate', 'https://shlink.io/new-visit/foo', null]; yield 'newShortUrlVisitUpdate' => ['newShortUrlVisitUpdate', 'https://shlink.io/new-visit/foo', null];
} }
/** #[Test, DataProvider('provideOrphanVisits')]
* @test
* @dataProvider provideOrphanVisits
*/
public function orphanVisitIsProperlySerializedIntoUpdate(Visit $orphanVisit): void public function orphanVisitIsProperlySerializedIntoUpdate(Visit $orphanVisit): void
{ {
$update = $this->generator->newOrphanVisitUpdate($orphanVisit); $update = $this->generator->newOrphanVisitUpdate($orphanVisit);
@ -105,7 +101,7 @@ class PublishingUpdatesGeneratorTest extends TestCase
], $update->payload); ], $update->payload);
} }
public function provideOrphanVisits(): iterable public static function provideOrphanVisits(): iterable
{ {
$visitor = Visitor::emptyInstance(); $visitor = Visitor::emptyInstance();
@ -114,7 +110,7 @@ class PublishingUpdatesGeneratorTest extends TestCase
yield VisitType::BASE_URL->value => [Visit::forBasePath($visitor)]; yield VisitType::BASE_URL->value => [Visit::forBasePath($visitor)];
} }
/** @test */ #[Test]
public function shortUrlIsProperlySerializedIntoUpdate(): void public function shortUrlIsProperlySerializedIntoUpdate(): void
{ {
$shortUrl = ShortUrl::create(ShortUrlCreation::fromRawData([ $shortUrl = ShortUrl::create(ShortUrlCreation::fromRawData([

View File

@ -7,6 +7,8 @@ namespace ShlinkioTest\Shlink\Core\EventDispatcher\RabbitMq;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use DomainException; use DomainException;
use Exception; use Exception;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
@ -36,7 +38,7 @@ class NotifyNewShortUrlToRabbitMqTest extends TestCase
$this->logger = $this->createMock(LoggerInterface::class); $this->logger = $this->createMock(LoggerInterface::class);
} }
/** @test */ #[Test]
public function doesNothingWhenTheFeatureIsNotEnabled(): void public function doesNothingWhenTheFeatureIsNotEnabled(): void
{ {
$this->helper->expects($this->never())->method('publishUpdate'); $this->helper->expects($this->never())->method('publishUpdate');
@ -47,7 +49,7 @@ class NotifyNewShortUrlToRabbitMqTest extends TestCase
($this->listener(false))(new ShortUrlCreated('123')); ($this->listener(false))(new ShortUrlCreated('123'));
} }
/** @test */ #[Test]
public function notificationsAreNotSentWhenShortUrlCannotBeFound(): void public function notificationsAreNotSentWhenShortUrlCannotBeFound(): void
{ {
$shortUrlId = '123'; $shortUrlId = '123';
@ -62,7 +64,7 @@ class NotifyNewShortUrlToRabbitMqTest extends TestCase
($this->listener())(new ShortUrlCreated($shortUrlId)); ($this->listener())(new ShortUrlCreated($shortUrlId));
} }
/** @test */ #[Test]
public function expectedChannelIsNotified(): void public function expectedChannelIsNotified(): void
{ {
$shortUrlId = '123'; $shortUrlId = '123';
@ -79,10 +81,7 @@ class NotifyNewShortUrlToRabbitMqTest extends TestCase
($this->listener())(new ShortUrlCreated($shortUrlId)); ($this->listener())(new ShortUrlCreated($shortUrlId));
} }
/** #[Test, DataProvider('provideExceptions')]
* @test
* @dataProvider provideExceptions
*/
public function printsDebugMessageInCaseOfError(Throwable $e): void public function printsDebugMessageInCaseOfError(Throwable $e): void
{ {
$shortUrlId = '123'; $shortUrlId = '123';
@ -102,7 +101,7 @@ class NotifyNewShortUrlToRabbitMqTest extends TestCase
($this->listener())(new ShortUrlCreated($shortUrlId)); ($this->listener())(new ShortUrlCreated($shortUrlId));
} }
public function provideExceptions(): iterable public static function provideExceptions(): iterable
{ {
yield [new RuntimeException('RuntimeException Error')]; yield [new RuntimeException('RuntimeException Error')];
yield [new Exception('Exception Error')]; yield [new Exception('Exception Error')];

View File

@ -8,6 +8,8 @@ use Doctrine\ORM\EntityManagerInterface;
use DomainException; use DomainException;
use Exception; use Exception;
use PHPUnit\Framework\Assert; use PHPUnit\Framework\Assert;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
@ -44,7 +46,7 @@ class NotifyVisitToRabbitMqTest extends TestCase
$this->logger = $this->createMock(LoggerInterface::class); $this->logger = $this->createMock(LoggerInterface::class);
} }
/** @test */ #[Test]
public function doesNothingWhenTheFeatureIsNotEnabled(): void public function doesNothingWhenTheFeatureIsNotEnabled(): void
{ {
$this->helper->expects($this->never())->method('publishUpdate'); $this->helper->expects($this->never())->method('publishUpdate');
@ -55,7 +57,7 @@ class NotifyVisitToRabbitMqTest extends TestCase
($this->listener(new RabbitMqOptions(enabled: false)))(new VisitLocated('123')); ($this->listener(new RabbitMqOptions(enabled: false)))(new VisitLocated('123'));
} }
/** @test */ #[Test]
public function notificationsAreNotSentWhenVisitCannotBeFound(): void public function notificationsAreNotSentWhenVisitCannotBeFound(): void
{ {
$visitId = '123'; $visitId = '123';
@ -70,10 +72,7 @@ class NotifyVisitToRabbitMqTest extends TestCase
($this->listener())(new VisitLocated($visitId)); ($this->listener())(new VisitLocated($visitId));
} }
/** #[Test, DataProvider('provideVisits')]
* @test
* @dataProvider provideVisits
*/
public function expectedChannelsAreNotifiedBasedOnTheVisitType(Visit $visit, array $expectedChannels): void public function expectedChannelsAreNotifiedBasedOnTheVisitType(Visit $visit, array $expectedChannels): void
{ {
$visitId = '123'; $visitId = '123';
@ -91,7 +90,7 @@ class NotifyVisitToRabbitMqTest extends TestCase
($this->listener())(new VisitLocated($visitId)); ($this->listener())(new VisitLocated($visitId));
} }
public function provideVisits(): iterable public static function provideVisits(): iterable
{ {
$visitor = Visitor::emptyInstance(); $visitor = Visitor::emptyInstance();
@ -108,10 +107,7 @@ class NotifyVisitToRabbitMqTest extends TestCase
]; ];
} }
/** #[Test, DataProvider('provideExceptions')]
* @test
* @dataProvider provideExceptions
*/
public function printsDebugMessageInCaseOfError(Throwable $e): void public function printsDebugMessageInCaseOfError(Throwable $e): void
{ {
$visitId = '123'; $visitId = '123';
@ -130,17 +126,14 @@ class NotifyVisitToRabbitMqTest extends TestCase
($this->listener())(new VisitLocated($visitId)); ($this->listener())(new VisitLocated($visitId));
} }
public function provideExceptions(): iterable public static function provideExceptions(): iterable
{ {
yield [new RuntimeException('RuntimeException Error')]; yield [new RuntimeException('RuntimeException Error')];
yield [new Exception('Exception Error')]; yield [new Exception('Exception Error')];
yield [new DomainException('DomainException Error')]; yield [new DomainException('DomainException Error')];
} }
/** #[Test, DataProvider('provideLegacyPayloads')]
* @test
* @dataProvider provideLegacyPayloads
*/
public function expectedPayloadIsPublishedDependingOnConfig( public function expectedPayloadIsPublishedDependingOnConfig(
bool $legacy, bool $legacy,
Visit $visit, Visit $visit,
@ -155,14 +148,14 @@ class NotifyVisitToRabbitMqTest extends TestCase
($this->listener(new RabbitMqOptions(true, $legacy)))(new VisitLocated($visitId)); ($this->listener(new RabbitMqOptions(true, $legacy)))(new VisitLocated($visitId));
} }
public function provideLegacyPayloads(): iterable public static function provideLegacyPayloads(): iterable
{ {
yield 'legacy non-orphan visit' => [ yield 'legacy non-orphan visit' => [
true, true,
$visit = Visit::forValidShortUrl(ShortUrl::withLongUrl('longUrl'), Visitor::emptyInstance()), $visit = Visit::forValidShortUrl(ShortUrl::withLongUrl('longUrl'), Visitor::emptyInstance()),
noop(...), noop(...),
function (MockObject & PublishingHelperInterface $helper) use ($visit): void { function (MockObject & PublishingHelperInterface $helper) use ($visit): void {
$helper->method('publishUpdate')->with($this->callback(function (Update $update) use ($visit): bool { $helper->method('publishUpdate')->with(self::callback(function (Update $update) use ($visit): bool {
$payload = $update->payload; $payload = $update->payload;
Assert::assertEquals($payload, $visit->jsonSerialize()); Assert::assertEquals($payload, $visit->jsonSerialize());
Assert::assertArrayNotHasKey('visitedUrl', $payload); Assert::assertArrayNotHasKey('visitedUrl', $payload);
@ -179,7 +172,7 @@ class NotifyVisitToRabbitMqTest extends TestCase
Visit::forBasePath(Visitor::emptyInstance()), Visit::forBasePath(Visitor::emptyInstance()),
noop(...), noop(...),
function (MockObject & PublishingHelperInterface $helper): void { function (MockObject & PublishingHelperInterface $helper): void {
$helper->method('publishUpdate')->with($this->callback(function (Update $update): bool { $helper->method('publishUpdate')->with(self::callback(function (Update $update): bool {
$payload = $update->payload; $payload = $update->payload;
Assert::assertArrayHasKey('visitedUrl', $payload); Assert::assertArrayHasKey('visitedUrl', $payload);
Assert::assertArrayHasKey('type', $payload); Assert::assertArrayHasKey('type', $payload);
@ -193,14 +186,14 @@ class NotifyVisitToRabbitMqTest extends TestCase
Visit::forValidShortUrl(ShortUrl::withLongUrl('longUrl'), Visitor::emptyInstance()), Visit::forValidShortUrl(ShortUrl::withLongUrl('longUrl'), Visitor::emptyInstance()),
function (MockObject & PublishingUpdatesGeneratorInterface $updatesGenerator): void { function (MockObject & PublishingUpdatesGeneratorInterface $updatesGenerator): void {
$update = Update::forTopicAndPayload('', []); $update = Update::forTopicAndPayload('', []);
$updatesGenerator->expects($this->never())->method('newOrphanVisitUpdate'); $updatesGenerator->expects(self::never())->method('newOrphanVisitUpdate');
$updatesGenerator->expects($this->once())->method('newVisitUpdate')->withAnyParameters()->willReturn( $updatesGenerator->expects(self::once())->method('newVisitUpdate')->withAnyParameters()->willReturn(
$update, $update,
); );
$updatesGenerator->expects($this->once())->method('newShortUrlVisitUpdate')->willReturn($update); $updatesGenerator->expects(self::once())->method('newShortUrlVisitUpdate')->willReturn($update);
}, },
function (MockObject & PublishingHelperInterface $helper): void { function (MockObject & PublishingHelperInterface $helper): void {
$helper->expects($this->exactly(2))->method('publishUpdate')->with($this->isInstanceOf(Update::class)); $helper->expects(self::exactly(2))->method('publishUpdate')->with(self::isInstanceOf(Update::class));
}, },
]; ];
yield 'non-legacy orphan visit' => [ yield 'non-legacy orphan visit' => [
@ -208,12 +201,12 @@ class NotifyVisitToRabbitMqTest extends TestCase
Visit::forBasePath(Visitor::emptyInstance()), Visit::forBasePath(Visitor::emptyInstance()),
function (MockObject & PublishingUpdatesGeneratorInterface $updatesGenerator): void { function (MockObject & PublishingUpdatesGeneratorInterface $updatesGenerator): void {
$update = Update::forTopicAndPayload('', []); $update = Update::forTopicAndPayload('', []);
$updatesGenerator->expects($this->once())->method('newOrphanVisitUpdate')->willReturn($update); $updatesGenerator->expects(self::once())->method('newOrphanVisitUpdate')->willReturn($update);
$updatesGenerator->expects($this->never())->method('newVisitUpdate'); $updatesGenerator->expects(self::never())->method('newVisitUpdate');
$updatesGenerator->expects($this->never())->method('newShortUrlVisitUpdate'); $updatesGenerator->expects(self::never())->method('newShortUrlVisitUpdate');
}, },
function (MockObject & PublishingHelperInterface $helper): void { function (MockObject & PublishingHelperInterface $helper): void {
$helper->expects($this->once())->method('publishUpdate')->with($this->isInstanceOf(Update::class)); $helper->expects(self::once())->method('publishUpdate')->with(self::isInstanceOf(Update::class));
}, },
]; ];
} }

View File

@ -7,6 +7,8 @@ namespace ShlinkioTest\Shlink\Core\EventDispatcher\RedisPubSub;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use DomainException; use DomainException;
use Exception; use Exception;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
@ -35,7 +37,7 @@ class NotifyNewShortUrlToRedisTest extends TestCase
$this->logger = $this->createMock(LoggerInterface::class); $this->logger = $this->createMock(LoggerInterface::class);
} }
/** @test */ #[Test]
public function doesNothingWhenTheFeatureIsNotEnabled(): void public function doesNothingWhenTheFeatureIsNotEnabled(): void
{ {
$this->helper->expects($this->never())->method('publishUpdate'); $this->helper->expects($this->never())->method('publishUpdate');
@ -46,10 +48,7 @@ class NotifyNewShortUrlToRedisTest extends TestCase
$this->createListener(false)(new ShortUrlCreated('123')); $this->createListener(false)(new ShortUrlCreated('123'));
} }
/** #[Test, DataProvider('provideExceptions')]
* @test
* @dataProvider provideExceptions
*/
public function printsDebugMessageInCaseOfError(Throwable $e): void public function printsDebugMessageInCaseOfError(Throwable $e): void
{ {
$shortUrlId = '123'; $shortUrlId = '123';
@ -69,7 +68,7 @@ class NotifyNewShortUrlToRedisTest extends TestCase
$this->createListener()(new ShortUrlCreated($shortUrlId)); $this->createListener()(new ShortUrlCreated($shortUrlId));
} }
public function provideExceptions(): iterable public static function provideExceptions(): iterable
{ {
yield [new RuntimeException('RuntimeException Error')]; yield [new RuntimeException('RuntimeException Error')];
yield [new Exception('Exception Error')]; yield [new Exception('Exception Error')];

View File

@ -7,6 +7,8 @@ namespace ShlinkioTest\Shlink\Core\EventDispatcher\RedisPubSub;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use DomainException; use DomainException;
use Exception; use Exception;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
@ -35,7 +37,7 @@ class NotifyVisitToRedisTest extends TestCase
$this->logger = $this->createMock(LoggerInterface::class); $this->logger = $this->createMock(LoggerInterface::class);
} }
/** @test */ #[Test]
public function doesNothingWhenTheFeatureIsNotEnabled(): void public function doesNothingWhenTheFeatureIsNotEnabled(): void
{ {
$this->helper->expects($this->never())->method('publishUpdate'); $this->helper->expects($this->never())->method('publishUpdate');
@ -46,10 +48,7 @@ class NotifyVisitToRedisTest extends TestCase
$this->createListener(false)(new VisitLocated('123')); $this->createListener(false)(new VisitLocated('123'));
} }
/** #[Test, DataProvider('provideExceptions')]
* @test
* @dataProvider provideExceptions
*/
public function printsDebugMessageInCaseOfError(Throwable $e): void public function printsDebugMessageInCaseOfError(Throwable $e): void
{ {
$visitId = '123'; $visitId = '123';
@ -68,7 +67,7 @@ class NotifyVisitToRedisTest extends TestCase
$this->createListener()(new VisitLocated($visitId)); $this->createListener()(new VisitLocated($visitId));
} }
public function provideExceptions(): iterable public static function provideExceptions(): iterable
{ {
yield [new RuntimeException('RuntimeException Error')]; yield [new RuntimeException('RuntimeException Error')];
yield [new Exception('Exception Error')]; yield [new Exception('Exception Error')];

View File

@ -4,6 +4,8 @@ declare(strict_types=1);
namespace ShlinkioTest\Shlink\Core\EventDispatcher; namespace ShlinkioTest\Shlink\Core\EventDispatcher;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Psr\EventDispatcher\EventDispatcherInterface; use Psr\EventDispatcher\EventDispatcherInterface;
@ -32,7 +34,7 @@ class UpdateGeoLiteDbTest extends TestCase
$this->listener = new UpdateGeoLiteDb($this->dbUpdater, $this->logger, $this->eventDispatcher); $this->listener = new UpdateGeoLiteDb($this->dbUpdater, $this->logger, $this->eventDispatcher);
} }
/** @test */ #[Test]
public function exceptionWhileUpdatingDbLogsError(): void public function exceptionWhileUpdatingDbLogsError(): void
{ {
$e = new RuntimeException(); $e = new RuntimeException();
@ -48,10 +50,7 @@ class UpdateGeoLiteDbTest extends TestCase
($this->listener)(); ($this->listener)();
} }
/** #[Test, DataProvider('provideFlags')]
* @test
* @dataProvider provideFlags
*/
public function noticeMessageIsPrintedWhenFirstCallbackIsInvoked(bool $oldDbExists, string $expectedMessage): void public function noticeMessageIsPrintedWhenFirstCallbackIsInvoked(bool $oldDbExists, string $expectedMessage): void
{ {
$this->dbUpdater->expects($this->once())->method('checkDbUpdate')->withAnyParameters()->willReturnCallback( $this->dbUpdater->expects($this->once())->method('checkDbUpdate')->withAnyParameters()->willReturnCallback(
@ -67,16 +66,13 @@ class UpdateGeoLiteDbTest extends TestCase
($this->listener)(); ($this->listener)();
} }
public function provideFlags(): iterable public static function provideFlags(): iterable
{ {
yield 'existing old db' => [true, 'Updating GeoLite2 db file...']; yield 'existing old db' => [true, 'Updating GeoLite2 db file...'];
yield 'not existing old db' => [false, 'Downloading GeoLite2 db file...']; yield 'not existing old db' => [false, 'Downloading GeoLite2 db file...'];
} }
/** #[Test, DataProvider('provideDownloaded')]
* @test
* @dataProvider provideDownloaded
*/
public function noticeMessageIsPrintedWhenSecondCallbackIsInvoked( public function noticeMessageIsPrintedWhenSecondCallbackIsInvoked(
int $total, int $total,
int $downloaded, int $downloaded,
@ -101,7 +97,7 @@ class UpdateGeoLiteDbTest extends TestCase
($this->listener)(); ($this->listener)();
} }
public function provideDownloaded(): iterable public static function provideDownloaded(): iterable
{ {
yield [100, 0, true, null]; yield [100, 0, true, null];
yield [100, 0, false, null]; yield [100, 0, false, null];
@ -113,10 +109,7 @@ class UpdateGeoLiteDbTest extends TestCase
yield [100, 101, false, 'Finished downloading GeoLite2 db file']; yield [100, 101, false, 'Finished downloading GeoLite2 db file'];
} }
/** #[Test, DataProvider('provideGeolocationResults')]
* @test
* @dataProvider provideGeolocationResults
*/
public function dispatchesEventOnlyWhenDbFileHasBeenCreatedForTheFirstTime( public function dispatchesEventOnlyWhenDbFileHasBeenCreatedForTheFirstTime(
GeolocationResult $result, GeolocationResult $result,
int $expectedDispatches, int $expectedDispatches,
@ -129,7 +122,7 @@ class UpdateGeoLiteDbTest extends TestCase
($this->listener)(); ($this->listener)();
} }
public function provideGeolocationResults(): iterable public static function provideGeolocationResults(): iterable
{ {
return map(GeolocationResult::cases(), static fn (GeolocationResult $value) => [ return map(GeolocationResult::cases(), static fn (GeolocationResult $value) => [
$value, $value,

View File

@ -4,6 +4,8 @@ declare(strict_types=1);
namespace ShlinkioTest\Shlink\Core\Exception; namespace ShlinkioTest\Shlink\Core\Exception;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Shlinkio\Shlink\Core\Exception\DeleteShortUrlException; use Shlinkio\Shlink\Core\Exception\DeleteShortUrlException;
use Shlinkio\Shlink\Core\ShortUrl\Model\ShortUrlIdentifier; use Shlinkio\Shlink\Core\ShortUrl\Model\ShortUrlIdentifier;
@ -15,10 +17,7 @@ use function sprintf;
class DeleteShortUrlExceptionTest extends TestCase class DeleteShortUrlExceptionTest extends TestCase
{ {
/** #[Test, DataProvider('provideThresholds')]
* @test
* @dataProvider provideThresholds
*/
public function fromVisitsThresholdGeneratesMessageProperly( public function fromVisitsThresholdGeneratesMessageProperly(
int $threshold, int $threshold,
string $shortCode, string $shortCode,
@ -41,7 +40,7 @@ class DeleteShortUrlExceptionTest extends TestCase
self::assertEquals(422, $e->getStatus()); self::assertEquals(422, $e->getStatus());
} }
public function provideThresholds(): array public static function provideThresholds(): array
{ {
return map(range(5, 50, 5), function (int $number) { return map(range(5, 50, 5), function (int $number) {
return [$number, $shortCode = generateRandomShortCode(6), sprintf( return [$number, $shortCode = generateRandomShortCode(6), sprintf(
@ -52,7 +51,7 @@ class DeleteShortUrlExceptionTest extends TestCase
}); });
} }
/** @test */ #[Test]
public function domainIsPartOfAdditionalWhenProvidedInIdentifier(): void public function domainIsPartOfAdditionalWhenProvidedInIdentifier(): void
{ {
$e = DeleteShortUrlException::fromVisitsThreshold( $e = DeleteShortUrlException::fromVisitsThreshold(

View File

@ -4,6 +4,7 @@ declare(strict_types=1);
namespace ShlinkioTest\Shlink\Core\Exception; namespace ShlinkioTest\Shlink\Core\Exception;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Shlinkio\Shlink\Core\Exception\DomainNotFoundException; use Shlinkio\Shlink\Core\Exception\DomainNotFoundException;
@ -11,7 +12,7 @@ use function sprintf;
class DomainNotFoundExceptionTest extends TestCase class DomainNotFoundExceptionTest extends TestCase
{ {
/** @test */ #[Test]
public function properlyCreatesExceptionFromId(): void public function properlyCreatesExceptionFromId(): void
{ {
$id = '123'; $id = '123';
@ -26,7 +27,7 @@ class DomainNotFoundExceptionTest extends TestCase
self::assertEquals(404, $e->getStatus()); self::assertEquals(404, $e->getStatus());
} }
/** @test */ #[Test]
public function properlyCreatesExceptionFromAuthority(): void public function properlyCreatesExceptionFromAuthority(): void
{ {
$authority = 'example.com'; $authority = 'example.com';

View File

@ -4,15 +4,14 @@ declare(strict_types=1);
namespace ShlinkioTest\Shlink\Core\Exception; namespace ShlinkioTest\Shlink\Core\Exception;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Shlinkio\Shlink\Core\Exception\ForbiddenTagOperationException; use Shlinkio\Shlink\Core\Exception\ForbiddenTagOperationException;
class ForbiddenTagOperationExceptionTest extends TestCase class ForbiddenTagOperationExceptionTest extends TestCase
{ {
/** #[Test, DataProvider('provideExceptions')]
* @test
* @dataProvider provideExceptions
*/
public function createsExpectedExceptionForDeletion( public function createsExpectedExceptionForDeletion(
ForbiddenTagOperationException $e, ForbiddenTagOperationException $e,
string $expectedMessage, string $expectedMessage,
@ -29,7 +28,7 @@ class ForbiddenTagOperationExceptionTest extends TestCase
self::assertEquals(403, $e->getStatus()); self::assertEquals(403, $e->getStatus());
} }
public function provideExceptions(): iterable public static function provideExceptions(): iterable
{ {
yield 'deletion' => [ForbiddenTagOperationException::forDeletion(), 'You are not allowed to delete tags']; yield 'deletion' => [ForbiddenTagOperationException::forDeletion(), 'You are not allowed to delete tags'];
yield 'renaming' => [ForbiddenTagOperationException::forRenaming(), 'You are not allowed to rename tags']; yield 'renaming' => [ForbiddenTagOperationException::forRenaming(), 'You are not allowed to rename tags'];

View File

@ -6,6 +6,8 @@ namespace ShlinkioTest\Shlink\Core\Exception;
use Exception; use Exception;
use Fig\Http\Message\StatusCodeInterface; use Fig\Http\Message\StatusCodeInterface;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Shlinkio\Shlink\Core\Exception\InvalidUrlException; use Shlinkio\Shlink\Core\Exception\InvalidUrlException;
use Throwable; use Throwable;
@ -14,10 +16,7 @@ use function sprintf;
class InvalidUrlExceptionTest extends TestCase class InvalidUrlExceptionTest extends TestCase
{ {
/** #[Test, DataProvider('providePrevious')]
* @test
* @dataProvider providePrevious
*/
public function properlyCreatesExceptionFromUrl(?Throwable $prev): void public function properlyCreatesExceptionFromUrl(?Throwable $prev): void
{ {
$url = 'http://the_url.com'; $url = 'http://the_url.com';
@ -34,7 +33,7 @@ class InvalidUrlExceptionTest extends TestCase
self::assertEquals($prev, $e->getPrevious()); self::assertEquals($prev, $e->getPrevious());
} }
public function providePrevious(): iterable public static function providePrevious(): iterable
{ {
yield 'null previous' => [null]; yield 'null previous' => [null];
yield 'instance previous' => [new Exception('Previous error', 10)]; yield 'instance previous' => [new Exception('Previous error', 10)];

View File

@ -6,6 +6,8 @@ namespace ShlinkioTest\Shlink\Core\Exception;
use Exception; use Exception;
use LogicException; use LogicException;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Shlinkio\Shlink\Core\Exception\IpCannotBeLocatedException; use Shlinkio\Shlink\Core\Exception\IpCannotBeLocatedException;
use Shlinkio\Shlink\Core\Exception\RuntimeException; use Shlinkio\Shlink\Core\Exception\RuntimeException;
@ -14,7 +16,7 @@ use Throwable;
class IpCannotBeLocatedExceptionTest extends TestCase class IpCannotBeLocatedExceptionTest extends TestCase
{ {
/** @test */ #[Test]
public function forEmptyAddressInitializesException(): void public function forEmptyAddressInitializesException(): void
{ {
$e = IpCannotBeLocatedException::forEmptyAddress(); $e = IpCannotBeLocatedException::forEmptyAddress();
@ -26,7 +28,7 @@ class IpCannotBeLocatedExceptionTest extends TestCase
self::assertEquals(UnlocatableIpType::EMPTY_ADDRESS, $e->type); self::assertEquals(UnlocatableIpType::EMPTY_ADDRESS, $e->type);
} }
/** @test */ #[Test]
public function forLocalhostInitializesException(): void public function forLocalhostInitializesException(): void
{ {
$e = IpCannotBeLocatedException::forLocalhost(); $e = IpCannotBeLocatedException::forLocalhost();
@ -38,10 +40,7 @@ class IpCannotBeLocatedExceptionTest extends TestCase
self::assertEquals(UnlocatableIpType::LOCALHOST, $e->type); self::assertEquals(UnlocatableIpType::LOCALHOST, $e->type);
} }
/** #[Test, DataProvider('provideErrors')]
* @test
* @dataProvider provideErrors
*/
public function forErrorInitializesException(Throwable $prev): void public function forErrorInitializesException(Throwable $prev): void
{ {
$e = IpCannotBeLocatedException::forError($prev); $e = IpCannotBeLocatedException::forError($prev);
@ -53,7 +52,7 @@ class IpCannotBeLocatedExceptionTest extends TestCase
self::assertEquals(UnlocatableIpType::ERROR, $e->type); self::assertEquals(UnlocatableIpType::ERROR, $e->type);
} }
public function provideErrors(): iterable public static function provideErrors(): iterable
{ {
yield 'Simple exception with positive code' => [new Exception('Some message', 100)]; yield 'Simple exception with positive code' => [new Exception('Some message', 100)];
yield 'Runtime exception with negative code' => [new RuntimeException('Something went wrong', -50)]; yield 'Runtime exception with negative code' => [new RuntimeException('Something went wrong', -50)];

View File

@ -6,12 +6,13 @@ namespace ShlinkioTest\Shlink\Core\Exception;
use Fig\Http\Message\StatusCodeInterface; use Fig\Http\Message\StatusCodeInterface;
use JsonException; use JsonException;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Shlinkio\Shlink\Core\Exception\MalformedBodyException; use Shlinkio\Shlink\Core\Exception\MalformedBodyException;
class MalformedBodyExceptionTest extends TestCase class MalformedBodyExceptionTest extends TestCase
{ {
/** @test */ #[Test]
public function createsExpectedException(): void public function createsExpectedException(): void
{ {
$prev = new JsonException(); $prev = new JsonException();

View File

@ -4,15 +4,14 @@ declare(strict_types=1);
namespace ShlinkioTest\Shlink\Core\Exception; namespace ShlinkioTest\Shlink\Core\Exception;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Shlinkio\Shlink\Core\Exception\NonUniqueSlugException; use Shlinkio\Shlink\Core\Exception\NonUniqueSlugException;
class NonUniqueSlugExceptionTest extends TestCase class NonUniqueSlugExceptionTest extends TestCase
{ {
/** #[Test, DataProvider('provideMessages')]
* @test
* @dataProvider provideMessages
*/
public function properlyCreatesExceptionFromSlug(string $expectedMessage, string $slug, ?string $domain): void public function properlyCreatesExceptionFromSlug(string $expectedMessage, string $slug, ?string $domain): void
{ {
$expectedAdditional = ['customSlug' => $slug]; $expectedAdditional = ['customSlug' => $slug];
@ -30,7 +29,7 @@ class NonUniqueSlugExceptionTest extends TestCase
self::assertEquals($expectedAdditional, $e->getAdditionalData()); self::assertEquals($expectedAdditional, $e->getAdditionalData());
} }
public function provideMessages(): iterable public static function provideMessages(): iterable
{ {
yield 'without domain' => [ yield 'without domain' => [
'Provided slug "foo" is already in use.', 'Provided slug "foo" is already in use.',

View File

@ -4,16 +4,15 @@ declare(strict_types=1);
namespace ShlinkioTest\Shlink\Core\Exception; namespace ShlinkioTest\Shlink\Core\Exception;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Shlinkio\Shlink\Core\Exception\ShortUrlNotFoundException; use Shlinkio\Shlink\Core\Exception\ShortUrlNotFoundException;
use Shlinkio\Shlink\Core\ShortUrl\Model\ShortUrlIdentifier; use Shlinkio\Shlink\Core\ShortUrl\Model\ShortUrlIdentifier;
class ShortUrlNotFoundExceptionTest extends TestCase class ShortUrlNotFoundExceptionTest extends TestCase
{ {
/** #[Test, DataProvider('provideMessages')]
* @test
* @dataProvider provideMessages
*/
public function properlyCreatesExceptionFromNotFoundShortCode( public function properlyCreatesExceptionFromNotFoundShortCode(
string $expectedMessage, string $expectedMessage,
string $shortCode, string $shortCode,
@ -34,7 +33,7 @@ class ShortUrlNotFoundExceptionTest extends TestCase
self::assertEquals($expectedAdditional, $e->getAdditionalData()); self::assertEquals($expectedAdditional, $e->getAdditionalData());
} }
public function provideMessages(): iterable public static function provideMessages(): iterable
{ {
yield 'without domain' => [ yield 'without domain' => [
'No URL found with short code "abc123"', 'No URL found with short code "abc123"',

View File

@ -4,6 +4,7 @@ declare(strict_types=1);
namespace ShlinkioTest\Shlink\Core\Exception; namespace ShlinkioTest\Shlink\Core\Exception;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Shlinkio\Shlink\Core\Exception\TagConflictException; use Shlinkio\Shlink\Core\Exception\TagConflictException;
use Shlinkio\Shlink\Core\Tag\Model\TagRenaming; use Shlinkio\Shlink\Core\Tag\Model\TagRenaming;
@ -12,7 +13,7 @@ use function sprintf;
class TagConflictExceptionTest extends TestCase class TagConflictExceptionTest extends TestCase
{ {
/** @test */ #[Test]
public function properlyCreatesExceptionForExistingTag(): void public function properlyCreatesExceptionForExistingTag(): void
{ {
$oldName = 'foo'; $oldName = 'foo';

View File

@ -4,6 +4,7 @@ declare(strict_types=1);
namespace ShlinkioTest\Shlink\Core\Exception; namespace ShlinkioTest\Shlink\Core\Exception;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Shlinkio\Shlink\Core\Exception\TagNotFoundException; use Shlinkio\Shlink\Core\Exception\TagNotFoundException;
@ -11,7 +12,7 @@ use function sprintf;
class TagNotFoundExceptionTest extends TestCase class TagNotFoundExceptionTest extends TestCase
{ {
/** @test */ #[Test]
public function properlyCreatesExceptionFromNotFoundTag(): void public function properlyCreatesExceptionFromNotFoundTag(): void
{ {
$tag = 'foo'; $tag = 'foo';

View File

@ -7,6 +7,8 @@ namespace ShlinkioTest\Shlink\Core\Exception;
use Fig\Http\Message\StatusCodeInterface; use Fig\Http\Message\StatusCodeInterface;
use Laminas\InputFilter\InputFilterInterface; use Laminas\InputFilter\InputFilterInterface;
use LogicException; use LogicException;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use RuntimeException; use RuntimeException;
use Shlinkio\Shlink\Core\Exception\ValidationException; use Shlinkio\Shlink\Core\Exception\ValidationException;
@ -17,10 +19,7 @@ use function print_r;
class ValidationExceptionTest extends TestCase class ValidationExceptionTest extends TestCase
{ {
/** #[Test, DataProvider('provideExceptions')]
* @test
* @dataProvider provideExceptions
*/
public function createsExceptionFromInputFilter(?Throwable $prev): void public function createsExceptionFromInputFilter(?Throwable $prev): void
{ {
$invalidData = [ $invalidData = [
@ -46,7 +45,7 @@ class ValidationExceptionTest extends TestCase
self::assertStringContainsString($expectedStringRepresentation, (string) $e); self::assertStringContainsString($expectedStringRepresentation, (string) $e);
} }
public function provideExceptions(): iterable public static function provideExceptions(): iterable
{ {
return [[null], [new RuntimeException()], [new LogicException()]]; return [[null], [new RuntimeException()], [new LogicException()]];
} }

View File

@ -5,6 +5,8 @@ declare(strict_types=1);
namespace ShlinkioTest\Shlink\Core\Functions; namespace ShlinkioTest\Shlink\Core\Functions;
use BackedEnum; use BackedEnum;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Shlinkio\Shlink\Core\Config\EnvVars; use Shlinkio\Shlink\Core\Config\EnvVars;
use Shlinkio\Shlink\Core\Model\DeviceType; use Shlinkio\Shlink\Core\Model\DeviceType;
@ -18,15 +20,14 @@ class FunctionsTest extends TestCase
{ {
/** /**
* @param class-string<BackedEnum> $enum * @param class-string<BackedEnum> $enum
* @test
* @dataProvider provideEnums
*/ */
#[Test, DataProvider('provideEnums')]
public function enumValuesReturnsExpectedValueForEnum(string $enum, array $expectedValues): void public function enumValuesReturnsExpectedValueForEnum(string $enum, array $expectedValues): void
{ {
self::assertEquals($expectedValues, enumValues($enum)); self::assertEquals($expectedValues, enumValues($enum));
} }
public function provideEnums(): iterable public static function provideEnums(): iterable
{ {
yield EnvVars::class => [EnvVars::class, map(EnvVars::cases(), static fn (EnvVars $envVar) => $envVar->value)]; yield EnvVars::class => [EnvVars::class, map(EnvVars::cases(), static fn (EnvVars $envVar) => $envVar->value)];
yield VisitType::class => [ yield VisitType::class => [

View File

@ -7,6 +7,8 @@ namespace ShlinkioTest\Shlink\Core\Importer;
use Cake\Chronos\Chronos; use Cake\Chronos\Chronos;
use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use RuntimeException; use RuntimeException;
@ -61,7 +63,7 @@ class ImportedLinksProcessorTest extends TestCase
$this->io = $this->createMock(StyleInterface::class); $this->io = $this->createMock(StyleInterface::class);
} }
/** @test */ #[Test]
public function newUrlsWithNoErrorsAreAllPersisted(): void public function newUrlsWithNoErrorsAreAllPersisted(): void
{ {
$urls = [ $urls = [
@ -84,7 +86,7 @@ class ImportedLinksProcessorTest extends TestCase
$this->processor->process($this->io, ImportResult::withShortUrls($urls), $this->buildParams()); $this->processor->process($this->io, ImportResult::withShortUrls($urls), $this->buildParams());
} }
/** @test */ #[Test]
public function newUrlsWithErrorsAreSkipped(): void public function newUrlsWithErrorsAreSkipped(): void
{ {
$urls = [ $urls = [
@ -111,7 +113,7 @@ class ImportedLinksProcessorTest extends TestCase
self::assertEquals(1, $textCalls->skippedCount); self::assertEquals(1, $textCalls->skippedCount);
} }
/** @test */ #[Test]
public function alreadyImportedUrlsAreSkipped(): void public function alreadyImportedUrlsAreSkipped(): void
{ {
$urls = [ $urls = [
@ -137,7 +139,7 @@ class ImportedLinksProcessorTest extends TestCase
self::assertEquals(3, $textCalls->skippedCount); self::assertEquals(3, $textCalls->skippedCount);
} }
/** @test */ #[Test]
public function nonUniqueShortCodesAreAskedToUser(): void public function nonUniqueShortCodesAreAskedToUser(): void
{ {
$urls = [ $urls = [
@ -165,10 +167,7 @@ class ImportedLinksProcessorTest extends TestCase
self::assertEquals(3, $textCalls->skippedCount); self::assertEquals(3, $textCalls->skippedCount);
} }
/** #[Test, DataProvider('provideUrlsWithVisits')]
* @test
* @dataProvider provideUrlsWithVisits
*/
public function properAmountOfVisitsIsImported( public function properAmountOfVisitsIsImported(
ImportedShlinkUrl $importedUrl, ImportedShlinkUrl $importedUrl,
string $expectedOutput, string $expectedOutput,
@ -188,7 +187,7 @@ class ImportedLinksProcessorTest extends TestCase
$this->processor->process($this->io, ImportResult::withShortUrls([$importedUrl]), $this->buildParams()); $this->processor->process($this->io, ImportResult::withShortUrls([$importedUrl]), $this->buildParams());
} }
public function provideUrlsWithVisits(): iterable public static function provideUrlsWithVisits(): iterable
{ {
$now = Chronos::now(); $now = Chronos::now();
$createImportedUrl = static fn (array $visits) => $createImportedUrl = static fn (array $visits) =>
@ -230,9 +229,8 @@ class ImportedLinksProcessorTest extends TestCase
/** /**
* @param iterable<ImportedShlinkOrphanVisit> $visits * @param iterable<ImportedShlinkOrphanVisit> $visits
* @test
* @dataProvider provideOrphanVisits
*/ */
#[Test, DataProvider('provideOrphanVisits')]
public function properAmountOfOrphanVisitsIsImported( public function properAmountOfOrphanVisitsIsImported(
bool $importOrphanVisits, bool $importOrphanVisits,
iterable $visits, iterable $visits,
@ -262,7 +260,7 @@ class ImportedLinksProcessorTest extends TestCase
); );
} }
public function provideOrphanVisits(): iterable public static function provideOrphanVisits(): iterable
{ {
yield 'import orphan disable without visits' => [false, [], null, 0]; yield 'import orphan disable without visits' => [false, [], null, 0];
yield 'import orphan enabled without visits' => [true, [], null, 0]; yield 'import orphan enabled without visits' => [true, [], null, 0];

View File

@ -6,6 +6,7 @@ namespace ShlinkioTest\Shlink\Core\ShortUrl;
use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Shlinkio\Shlink\Core\Exception\DeleteShortUrlException; use Shlinkio\Shlink\Core\Exception\DeleteShortUrlException;
@ -40,7 +41,7 @@ class DeleteShortUrlServiceTest extends TestCase
$this->urlResolver->method('resolveShortUrl')->willReturn($shortUrl); $this->urlResolver->method('resolveShortUrl')->willReturn($shortUrl);
} }
/** @test */ #[Test]
public function deleteByShortCodeThrowsExceptionWhenThresholdIsReached(): void public function deleteByShortCodeThrowsExceptionWhenThresholdIsReached(): void
{ {
$service = $this->createService(); $service = $this->createService();
@ -54,7 +55,7 @@ class DeleteShortUrlServiceTest extends TestCase
$service->deleteByShortCode(ShortUrlIdentifier::fromShortCodeAndDomain($this->shortCode)); $service->deleteByShortCode(ShortUrlIdentifier::fromShortCodeAndDomain($this->shortCode));
} }
/** @test */ #[Test]
public function deleteByShortCodeDeletesUrlWhenThresholdIsReachedButExplicitlyIgnored(): void public function deleteByShortCodeDeletesUrlWhenThresholdIsReachedButExplicitlyIgnored(): void
{ {
$service = $this->createService(); $service = $this->createService();
@ -67,7 +68,7 @@ class DeleteShortUrlServiceTest extends TestCase
$service->deleteByShortCode(ShortUrlIdentifier::fromShortCodeAndDomain($this->shortCode), true); $service->deleteByShortCode(ShortUrlIdentifier::fromShortCodeAndDomain($this->shortCode), true);
} }
/** @test */ #[Test]
public function deleteByShortCodeDeletesUrlWhenThresholdIsReachedButCheckIsDisabled(): void public function deleteByShortCodeDeletesUrlWhenThresholdIsReachedButCheckIsDisabled(): void
{ {
$service = $this->createService(false); $service = $this->createService(false);
@ -80,7 +81,7 @@ class DeleteShortUrlServiceTest extends TestCase
$service->deleteByShortCode(ShortUrlIdentifier::fromShortCodeAndDomain($this->shortCode)); $service->deleteByShortCode(ShortUrlIdentifier::fromShortCodeAndDomain($this->shortCode));
} }
/** @test */ #[Test]
public function deleteByShortCodeDeletesUrlWhenThresholdIsNotReached(): void public function deleteByShortCodeDeletesUrlWhenThresholdIsNotReached(): void
{ {
$service = $this->createService(true, 100); $service = $this->createService(true, 100);

View File

@ -5,6 +5,8 @@ declare(strict_types=1);
namespace ShlinkioTest\Shlink\Core\ShortUrl\Entity; namespace ShlinkioTest\Shlink\Core\ShortUrl\Entity;
use Cake\Chronos\Chronos; use Cake\Chronos\Chronos;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Shlinkio\Shlink\Core\Exception\ShortCodeCannotBeRegeneratedException; use Shlinkio\Shlink\Core\Exception\ShortCodeCannotBeRegeneratedException;
use Shlinkio\Shlink\Core\Model\DeviceType; use Shlinkio\Shlink\Core\Model\DeviceType;
@ -27,10 +29,7 @@ use const Shlinkio\Shlink\DEFAULT_SHORT_CODES_LENGTH;
class ShortUrlTest extends TestCase class ShortUrlTest extends TestCase
{ {
/** #[Test, DataProvider('provideInvalidShortUrls')]
* @test
* @dataProvider provideInvalidShortUrls
*/
public function regenerateShortCodeThrowsExceptionIfStateIsInvalid( public function regenerateShortCodeThrowsExceptionIfStateIsInvalid(
ShortUrl $shortUrl, ShortUrl $shortUrl,
string $expectedMessage, string $expectedMessage,
@ -41,7 +40,7 @@ class ShortUrlTest extends TestCase
$shortUrl->regenerateShortCode(ShortUrlMode::STRICT); $shortUrl->regenerateShortCode(ShortUrlMode::STRICT);
} }
public function provideInvalidShortUrls(): iterable public static function provideInvalidShortUrls(): iterable
{ {
yield 'with custom slug' => [ yield 'with custom slug' => [
ShortUrl::create(ShortUrlCreation::fromRawData(['customSlug' => 'custom-slug', 'longUrl' => 'longUrl'])), ShortUrl::create(ShortUrlCreation::fromRawData(['customSlug' => 'custom-slug', 'longUrl' => 'longUrl'])),
@ -53,10 +52,7 @@ class ShortUrlTest extends TestCase
]; ];
} }
/** #[Test, DataProvider('provideValidShortUrls')]
* @test
* @dataProvider provideValidShortUrls
*/
public function regenerateShortCodeProperlyChangesTheValueOnValidShortUrls( public function regenerateShortCodeProperlyChangesTheValueOnValidShortUrls(
ShortUrl $shortUrl, ShortUrl $shortUrl,
): void { ): void {
@ -68,7 +64,7 @@ class ShortUrlTest extends TestCase
self::assertNotEquals($firstShortCode, $secondShortCode); self::assertNotEquals($firstShortCode, $secondShortCode);
} }
public function provideValidShortUrls(): iterable public static function provideValidShortUrls(): iterable
{ {
yield 'no custom slug' => [ShortUrl::createFake()]; yield 'no custom slug' => [ShortUrl::createFake()];
yield 'imported with custom slug' => [ShortUrl::fromImport( yield 'imported with custom slug' => [ShortUrl::fromImport(
@ -77,10 +73,7 @@ class ShortUrlTest extends TestCase
)]; )];
} }
/** #[Test, DataProvider('provideLengths')]
* @test
* @dataProvider provideLengths
*/
public function shortCodesHaveExpectedLength(?int $length, int $expectedLength): void public function shortCodesHaveExpectedLength(?int $length, int $expectedLength): void
{ {
$shortUrl = ShortUrl::create(ShortUrlCreation::fromRawData( $shortUrl = ShortUrl::create(ShortUrlCreation::fromRawData(
@ -90,13 +83,13 @@ class ShortUrlTest extends TestCase
self::assertEquals($expectedLength, strlen($shortUrl->getShortCode())); self::assertEquals($expectedLength, strlen($shortUrl->getShortCode()));
} }
public function provideLengths(): iterable public static function provideLengths(): iterable
{ {
yield [null, DEFAULT_SHORT_CODES_LENGTH]; yield [null, DEFAULT_SHORT_CODES_LENGTH];
yield from map(range(4, 10), fn (int $value) => [$value, $value]); yield from map(range(4, 10), fn (int $value) => [$value, $value]);
} }
/** @test */ #[Test]
public function deviceLongUrlsAreUpdated(): void public function deviceLongUrlsAreUpdated(): void
{ {
$shortUrl = ShortUrl::withLongUrl('foo'); $shortUrl = ShortUrl::withLongUrl('foo');
@ -138,7 +131,7 @@ class ShortUrlTest extends TestCase
], $shortUrl->deviceLongUrls()); ], $shortUrl->deviceLongUrls());
} }
/** @test */ #[Test]
public function generatesLowercaseOnlyShortCodesInLooseMode(): void public function generatesLowercaseOnlyShortCodesInLooseMode(): void
{ {
$range = range(1, 1000); // Use a "big" number to reduce false negatives $range = range(1, 1000); // Use a "big" number to reduce false negatives

View File

@ -5,6 +5,8 @@ declare(strict_types=1);
namespace ShlinkioTest\Shlink\Core\ShortUrl\Helper; namespace ShlinkioTest\Shlink\Core\ShortUrl\Helper;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Shlinkio\Shlink\Core\Domain\Entity\Domain; use Shlinkio\Shlink\Core\Domain\Entity\Domain;
@ -29,10 +31,7 @@ class ShortCodeUniquenessHelperTest extends TestCase
$this->shortUrl->method('getShortCode')->willReturn('abc123'); $this->shortUrl->method('getShortCode')->willReturn('abc123');
} }
/** #[Test, DataProvider('provideDomains')]
* @test
* @dataProvider provideDomains
*/
public function shortCodeIsRegeneratedIfAlreadyInUse(?Domain $domain, ?string $expectedAuthority): void public function shortCodeIsRegeneratedIfAlreadyInUse(?Domain $domain, ?string $expectedAuthority): void
{ {
$callIndex = 0; $callIndex = 0;
@ -55,13 +54,13 @@ class ShortCodeUniquenessHelperTest extends TestCase
self::assertTrue($result); self::assertTrue($result);
} }
public function provideDomains(): iterable public static function provideDomains(): iterable
{ {
yield 'no domain' => [null, null]; yield 'no domain' => [null, null];
yield 'domain' => [Domain::withAuthority($authority = 's.test'), $authority]; yield 'domain' => [Domain::withAuthority($authority = 's.test'), $authority];
} }
/** @test */ #[Test]
public function inUseSlugReturnsError(): void public function inUseSlugReturnsError(): void
{ {
$repo = $this->createMock(ShortUrlRepository::class); $repo = $this->createMock(ShortUrlRepository::class);

View File

@ -5,6 +5,8 @@ declare(strict_types=1);
namespace ShlinkioTest\Shlink\Core\ShortUrl\Helper; namespace ShlinkioTest\Shlink\Core\ShortUrl\Helper;
use Laminas\Diactoros\ServerRequestFactory; use Laminas\Diactoros\ServerRequestFactory;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ServerRequestInterface;
use Shlinkio\Shlink\Core\Model\DeviceType; use Shlinkio\Shlink\Core\Model\DeviceType;
@ -27,10 +29,7 @@ class ShortUrlRedirectionBuilderTest extends TestCase
$this->redirectionBuilder = new ShortUrlRedirectionBuilder($trackingOptions); $this->redirectionBuilder = new ShortUrlRedirectionBuilder($trackingOptions);
} }
/** #[Test, DataProvider('provideData')]
* @test
* @dataProvider provideData
*/
public function buildShortUrlRedirectBuildsExpectedUrl( public function buildShortUrlRedirectBuildsExpectedUrl(
string $expectedUrl, string $expectedUrl,
ServerRequestInterface $request, ServerRequestInterface $request,
@ -50,7 +49,7 @@ class ShortUrlRedirectionBuilderTest extends TestCase
self::assertEquals($expectedUrl, $result); self::assertEquals($expectedUrl, $result);
} }
public function provideData(): iterable public static function provideData(): iterable
{ {
$request = static fn (array $query = []) => ServerRequestFactory::fromGlobals()->withQueryParams($query); $request = static fn (array $query = []) => ServerRequestFactory::fromGlobals()->withQueryParams($query);

View File

@ -4,6 +4,8 @@ declare(strict_types=1);
namespace ShlinkioTest\Shlink\Core\ShortUrl\Helper; namespace ShlinkioTest\Shlink\Core\ShortUrl\Helper;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Shlinkio\Shlink\Core\ShortUrl\Entity\ShortUrl; use Shlinkio\Shlink\Core\ShortUrl\Entity\ShortUrl;
use Shlinkio\Shlink\Core\ShortUrl\Helper\ShortUrlStringifier; use Shlinkio\Shlink\Core\ShortUrl\Helper\ShortUrlStringifier;
@ -11,10 +13,7 @@ use Shlinkio\Shlink\Core\ShortUrl\Model\ShortUrlCreation;
class ShortUrlStringifierTest extends TestCase class ShortUrlStringifierTest extends TestCase
{ {
/** #[Test, DataProvider('provideConfigAndShortUrls')]
* @test
* @dataProvider provideConfigAndShortUrls
*/
public function generatesExpectedOutputBasedOnConfigAndShortUrl( public function generatesExpectedOutputBasedOnConfigAndShortUrl(
array $config, array $config,
string $basePath, string $basePath,
@ -26,7 +25,7 @@ class ShortUrlStringifierTest extends TestCase
self::assertEquals($expected, $stringifier->stringify($shortUrl)); self::assertEquals($expected, $stringifier->stringify($shortUrl));
} }
public function provideConfigAndShortUrls(): iterable public static function provideConfigAndShortUrls(): iterable
{ {
$shortUrlWithShortCode = fn (string $shortCode, ?string $domain = null) => ShortUrl::create( $shortUrlWithShortCode = fn (string $shortCode, ?string $domain = null) => ShortUrl::create(
ShortUrlCreation::fromRawData([ ShortUrlCreation::fromRawData([

View File

@ -4,6 +4,8 @@ declare(strict_types=1);
namespace ShlinkioTest\Shlink\Core\ShortUrl\Helper; namespace ShlinkioTest\Shlink\Core\ShortUrl\Helper;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Shlinkio\Shlink\Core\ShortUrl\Helper\ShortUrlTitleResolutionHelper; use Shlinkio\Shlink\Core\ShortUrl\Helper\ShortUrlTitleResolutionHelper;
@ -21,10 +23,7 @@ class ShortUrlTitleResolutionHelperTest extends TestCase
$this->helper = new ShortUrlTitleResolutionHelper($this->urlValidator); $this->helper = new ShortUrlTitleResolutionHelper($this->urlValidator);
} }
/** #[Test, DataProvider('provideTitles')]
* @test
* @dataProvider provideTitles
*/
public function urlIsProperlyShortened(?string $title, int $validateWithTitleCallsNum, int $validateCallsNum): void public function urlIsProperlyShortened(?string $title, int $validateWithTitleCallsNum, int $validateCallsNum): void
{ {
$longUrl = 'http://foobar.com/12345/hello?foo=bar'; $longUrl = 'http://foobar.com/12345/hello?foo=bar';
@ -42,7 +41,7 @@ class ShortUrlTitleResolutionHelperTest extends TestCase
); );
} }
public function provideTitles(): iterable public static function provideTitles(): iterable
{ {
yield 'no title' => [null, 1, 0]; yield 'no title' => [null, 1, 0];
yield 'title' => ['link title', 0, 1]; yield 'title' => ['link title', 0, 1];

View File

@ -9,10 +9,11 @@ use Laminas\Diactoros\ServerRequestFactory;
use Laminas\Diactoros\Uri; use Laminas\Diactoros\Uri;
use Mezzio\Router\Route; use Mezzio\Router\Route;
use Mezzio\Router\RouteResult; use Mezzio\Router\RouteResult;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface; use Psr\Http\Server\RequestHandlerInterface;
use Shlinkio\Shlink\Core\Action\RedirectAction; use Shlinkio\Shlink\Core\Action\RedirectAction;
use Shlinkio\Shlink\Core\ErrorHandler\Model\NotFoundType; use Shlinkio\Shlink\Core\ErrorHandler\Model\NotFoundType;
@ -26,6 +27,7 @@ use Shlinkio\Shlink\Core\ShortUrl\ShortUrlResolverInterface;
use Shlinkio\Shlink\Core\Util\RedirectResponseHelperInterface; use Shlinkio\Shlink\Core\Util\RedirectResponseHelperInterface;
use Shlinkio\Shlink\Core\Visit\RequestTrackerInterface; use Shlinkio\Shlink\Core\Visit\RequestTrackerInterface;
use function Laminas\Stratigility\middleware;
use function str_starts_with; use function str_starts_with;
class ExtraPathRedirectMiddlewareTest extends TestCase class ExtraPathRedirectMiddlewareTest extends TestCase
@ -46,10 +48,7 @@ class ExtraPathRedirectMiddlewareTest extends TestCase
$this->handler->method('handle')->willReturn(new RedirectResponse('')); $this->handler->method('handle')->willReturn(new RedirectResponse(''));
} }
/** #[Test, DataProvider('provideNonRedirectingRequests')]
* @test
* @dataProvider provideNonRedirectingRequests
*/
public function handlerIsCalledWhenConfigPreventsRedirectWithExtraPath( public function handlerIsCalledWhenConfigPreventsRedirectWithExtraPath(
bool $appendExtraPath, bool $appendExtraPath,
bool $multiSegmentEnabled, bool $multiSegmentEnabled,
@ -68,7 +67,7 @@ class ExtraPathRedirectMiddlewareTest extends TestCase
$this->middleware($options)->process($request, $this->handler); $this->middleware($options)->process($request, $this->handler);
} }
public function provideNonRedirectingRequests(): iterable public static function provideNonRedirectingRequests(): iterable
{ {
$baseReq = ServerRequestFactory::fromGlobals(); $baseReq = ServerRequestFactory::fromGlobals();
$buildReq = static fn (?NotFoundType $type): ServerRequestInterface => $buildReq = static fn (?NotFoundType $type): ServerRequestInterface =>
@ -84,7 +83,8 @@ class ExtraPathRedirectMiddlewareTest extends TestCase
RouteResult::class, RouteResult::class,
RouteResult::fromRoute(new Route( RouteResult::fromRoute(new Route(
'/foo', '/foo',
$this->createMock(MiddlewareInterface::class), middleware(function (): void {
}),
['GET'], ['GET'],
RedirectAction::class, RedirectAction::class,
)), )),
@ -100,10 +100,7 @@ class ExtraPathRedirectMiddlewareTest extends TestCase
]; ];
} }
/** #[Test, DataProvider('provideResolves')]
* @test
* @dataProvider provideResolves
*/
public function handlerIsCalledWhenNoShortUrlIsFoundAfterExpectedAmountOfIterations( public function handlerIsCalledWhenNoShortUrlIsFoundAfterExpectedAmountOfIterations(
bool $multiSegmentEnabled, bool $multiSegmentEnabled,
int $expectedResolveCalls, int $expectedResolveCalls,
@ -126,10 +123,7 @@ class ExtraPathRedirectMiddlewareTest extends TestCase
$this->middleware($options)->process($request, $this->handler); $this->middleware($options)->process($request, $this->handler);
} }
/** #[Test, DataProvider('provideResolves')]
* @test
* @dataProvider provideResolves
*/
public function visitIsTrackedAndRedirectIsReturnedWhenShortUrlIsFoundAfterExpectedAmountOfIterations( public function visitIsTrackedAndRedirectIsReturnedWhenShortUrlIsFoundAfterExpectedAmountOfIterations(
bool $multiSegmentEnabled, bool $multiSegmentEnabled,
int $expectedResolveCalls, int $expectedResolveCalls,
@ -170,7 +164,7 @@ class ExtraPathRedirectMiddlewareTest extends TestCase
$this->middleware($options)->process($request, $this->handler); $this->middleware($options)->process($request, $this->handler);
} }
public function provideResolves(): iterable public static function provideResolves(): iterable
{ {
yield [false, 1, '/bar/baz']; yield [false, 1, '/bar/baz'];
yield [true, 3, null]; yield [true, 3, null];

View File

@ -7,6 +7,8 @@ namespace ShlinkioTest\Shlink\Core\ShortUrl\Middleware;
use Laminas\Diactoros\Response; use Laminas\Diactoros\Response;
use Laminas\Diactoros\ServerRequestFactory; use Laminas\Diactoros\ServerRequestFactory;
use PHPUnit\Framework\Assert; use PHPUnit\Framework\Assert;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ServerRequestInterface;
@ -26,10 +28,7 @@ class TrimTrailingSlashMiddlewareTest extends TestCase
$this->requestHandler = $this->createMock(RequestHandlerInterface::class); $this->requestHandler = $this->createMock(RequestHandlerInterface::class);
} }
/** #[Test, DataProvider('provideRequests')]
* @test
* @dataProvider provideRequests
*/
public function returnsExpectedResponse( public function returnsExpectedResponse(
bool $trailingSlashEnabled, bool $trailingSlashEnabled,
ServerRequestInterface $inputRequest, ServerRequestInterface $inputRequest,
@ -43,7 +42,7 @@ class TrimTrailingSlashMiddlewareTest extends TestCase
$this->middleware($trailingSlashEnabled)->process($inputRequest, $this->requestHandler); $this->middleware($trailingSlashEnabled)->process($inputRequest, $this->requestHandler);
} }
public function provideRequests(): iterable public static function provideRequests(): iterable
{ {
yield 'trailing slash disabled' => [ yield 'trailing slash disabled' => [
false, false,

View File

@ -5,6 +5,8 @@ declare(strict_types=1);
namespace ShlinkioTest\Shlink\Core\ShortUrl\Model; namespace ShlinkioTest\Shlink\Core\ShortUrl\Model;
use Cake\Chronos\Chronos; use Cake\Chronos\Chronos;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Shlinkio\Shlink\Core\Exception\ValidationException; use Shlinkio\Shlink\Core\Exception\ValidationException;
use Shlinkio\Shlink\Core\Model\DeviceType; use Shlinkio\Shlink\Core\Model\DeviceType;
@ -20,18 +22,14 @@ use const STR_PAD_BOTH;
class ShortUrlCreationTest extends TestCase class ShortUrlCreationTest extends TestCase
{ {
/** #[Test, DataProvider('provideInvalidData')]
* @param array $data
* @test
* @dataProvider provideInvalidData
*/
public function exceptionIsThrownIfProvidedDataIsInvalid(array $data): void public function exceptionIsThrownIfProvidedDataIsInvalid(array $data): void
{ {
$this->expectException(ValidationException::class); $this->expectException(ValidationException::class);
ShortUrlCreation::fromRawData($data); ShortUrlCreation::fromRawData($data);
} }
public function provideInvalidData(): iterable public static function provideInvalidData(): iterable
{ {
yield [[]]; yield [[]];
yield [[ yield [[
@ -107,10 +105,7 @@ class ShortUrlCreationTest extends TestCase
]]; ]];
} }
/** #[Test, DataProvider('provideCustomSlugs')]
* @test
* @dataProvider provideCustomSlugs
*/
public function properlyCreatedInstanceReturnsValues( public function properlyCreatedInstanceReturnsValues(
string $customSlug, string $customSlug,
string $expectedSlug, string $expectedSlug,
@ -136,7 +131,7 @@ class ShortUrlCreationTest extends TestCase
self::assertNull($creation->maxVisits); self::assertNull($creation->maxVisits);
} }
public function provideCustomSlugs(): iterable public static function provideCustomSlugs(): iterable
{ {
yield ['🔥', '🔥']; yield ['🔥', '🔥'];
yield ['🦣 🍅', '🦣-🍅']; yield ['🦣 🍅', '🦣-🍅'];
@ -161,10 +156,7 @@ class ShortUrlCreationTest extends TestCase
yield ['гугл', 'гугл']; yield ['гугл', 'гугл'];
} }
/** #[Test, DataProvider('provideTitles')]
* @test
* @dataProvider provideTitles
*/
public function titleIsCroppedIfTooLong(?string $title, ?string $expectedTitle): void public function titleIsCroppedIfTooLong(?string $title, ?string $expectedTitle): void
{ {
$creation = ShortUrlCreation::fromRawData([ $creation = ShortUrlCreation::fromRawData([
@ -175,7 +167,7 @@ class ShortUrlCreationTest extends TestCase
self::assertEquals($expectedTitle, $creation->title); self::assertEquals($expectedTitle, $creation->title);
} }
public function provideTitles(): iterable public static function provideTitles(): iterable
{ {
yield [null, null]; yield [null, null];
yield ['foo', 'foo']; yield ['foo', 'foo'];
@ -187,10 +179,7 @@ class ShortUrlCreationTest extends TestCase
yield [str_pad('', 800, 'e'), str_pad('', 512, 'e')]; yield [str_pad('', 800, 'e'), str_pad('', 512, 'e')];
} }
/** #[Test, DataProvider('provideDomains')]
* @test
* @dataProvider provideDomains
*/
public function emptyDomainIsDiscarded(?string $domain, ?string $expectedDomain): void public function emptyDomainIsDiscarded(?string $domain, ?string $expectedDomain): void
{ {
$creation = ShortUrlCreation::fromRawData([ $creation = ShortUrlCreation::fromRawData([
@ -201,7 +190,7 @@ class ShortUrlCreationTest extends TestCase
self::assertSame($expectedDomain, $creation->domain); self::assertSame($expectedDomain, $creation->domain);
} }
public function provideDomains(): iterable public static function provideDomains(): iterable
{ {
yield 'null domain' => [null, null]; yield 'null domain' => [null, null];
yield 'empty domain' => ['', null]; yield 'empty domain' => ['', null];

View File

@ -4,6 +4,8 @@ declare(strict_types=1);
namespace ShlinkioTest\Shlink\Core\ShortUrl\Model; namespace ShlinkioTest\Shlink\Core\ShortUrl\Model;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Shlinkio\Shlink\Core\Model\DeviceType; use Shlinkio\Shlink\Core\Model\DeviceType;
use Shlinkio\Shlink\Core\ShortUrl\Model\DeviceLongUrlPair; use Shlinkio\Shlink\Core\ShortUrl\Model\DeviceLongUrlPair;
@ -12,10 +14,7 @@ use Shlinkio\Shlink\Core\ShortUrl\Model\Validation\ShortUrlInputFilter;
class ShortUrlEditionTest extends TestCase class ShortUrlEditionTest extends TestCase
{ {
/** #[Test, DataProvider('provideDeviceLongUrls')]
* @test
* @dataProvider provideDeviceLongUrls
*/
public function expectedDeviceLongUrlsAreResolved( public function expectedDeviceLongUrlsAreResolved(
?array $deviceLongUrls, ?array $deviceLongUrls,
array $expectedDeviceLongUrls, array $expectedDeviceLongUrls,
@ -27,7 +26,7 @@ class ShortUrlEditionTest extends TestCase
self::assertEquals($expectedDevicesToRemove, $edition->devicesToRemove); self::assertEquals($expectedDevicesToRemove, $edition->devicesToRemove);
} }
public function provideDeviceLongUrls(): iterable public static function provideDeviceLongUrls(): iterable
{ {
yield 'null' => [null, [], []]; yield 'null' => [null, [], []];
yield 'empty' => [[], [], []]; yield 'empty' => [[], [], []];

View File

@ -4,21 +4,20 @@ declare(strict_types=1);
namespace ShlinkioTest\Shlink\Core\ShortUrl\Model; namespace ShlinkioTest\Shlink\Core\ShortUrl\Model;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Shlinkio\Shlink\Core\ShortUrl\Model\ShortUrlMode; use Shlinkio\Shlink\Core\ShortUrl\Model\ShortUrlMode;
class ShortUrlModeTest extends TestCase class ShortUrlModeTest extends TestCase
{ {
/** #[Test, DataProvider('provideModes')]
* @test
* @dataProvider provideModes
*/
public function deprecatedValuesAreProperlyParsed(string $mode, ?ShortUrlMode $expected): void public function deprecatedValuesAreProperlyParsed(string $mode, ?ShortUrlMode $expected): void
{ {
self::assertSame($expected, ShortUrlMode::tryDeprecated($mode)); self::assertSame($expected, ShortUrlMode::tryDeprecated($mode));
} }
public function provideModes(): iterable public static function provideModes(): iterable
{ {
yield 'invalid' => ['invalid', null]; yield 'invalid' => ['invalid', null];
yield 'foo' => ['foo', null]; yield 'foo' => ['foo', null];

View File

@ -5,6 +5,8 @@ declare(strict_types=1);
namespace ShlinkioTest\Shlink\Core\ShortUrl\Model\Validation; namespace ShlinkioTest\Shlink\Core\ShortUrl\Model\Validation;
use Laminas\Validator\NotEmpty; use Laminas\Validator\NotEmpty;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Shlinkio\Shlink\Core\Model\DeviceType; use Shlinkio\Shlink\Core\Model\DeviceType;
use Shlinkio\Shlink\Core\ShortUrl\Model\Validation\DeviceLongUrlsValidator; use Shlinkio\Shlink\Core\ShortUrl\Model\Validation\DeviceLongUrlsValidator;
@ -19,17 +21,14 @@ class DeviceLongUrlsValidatorTest extends TestCase
$this->validator = new DeviceLongUrlsValidator(new NotEmpty()); $this->validator = new DeviceLongUrlsValidator(new NotEmpty());
} }
/** #[Test, DataProvider('provideNonArrayValues')]
* @test
* @dataProvider provideNonArrayValues
*/
public function nonArrayValuesAreNotValid(mixed $invalidValue): void public function nonArrayValuesAreNotValid(mixed $invalidValue): void
{ {
self::assertFalse($this->validator->isValid($invalidValue)); self::assertFalse($this->validator->isValid($invalidValue));
self::assertEquals(['NOT_ARRAY' => 'Provided value is not an array.'], $this->validator->getMessages()); self::assertEquals(['NOT_ARRAY' => 'Provided value is not an array.'], $this->validator->getMessages());
} }
public function provideNonArrayValues(): iterable public static function provideNonArrayValues(): iterable
{ {
yield 'int' => [0]; yield 'int' => [0];
yield 'float' => [100.45]; yield 'float' => [100.45];
@ -39,7 +38,7 @@ class DeviceLongUrlsValidatorTest extends TestCase
yield 'null' => [null]; yield 'null' => [null];
} }
/** @test */ #[Test]
public function unrecognizedKeysAreNotValid(): void public function unrecognizedKeysAreNotValid(): void
{ {
self::assertFalse($this->validator->isValid(['foo' => 'bar'])); self::assertFalse($this->validator->isValid(['foo' => 'bar']));
@ -49,7 +48,7 @@ class DeviceLongUrlsValidatorTest extends TestCase
); );
} }
/** @test */ #[Test]
public function everyUrlMustMatchLongUrlValidator(): void public function everyUrlMustMatchLongUrlValidator(): void
{ {
self::assertFalse($this->validator->isValid([DeviceType::ANDROID->value => ''])); self::assertFalse($this->validator->isValid([DeviceType::ANDROID->value => '']));
@ -59,7 +58,7 @@ class DeviceLongUrlsValidatorTest extends TestCase
); );
} }
/** @test */ #[Test]
public function validValuesResultInValidResult(): void public function validValuesResultInValidResult(): void
{ {
self::assertTrue($this->validator->isValid([ self::assertTrue($this->validator->isValid([

Some files were not shown because too many files have changed in this diff Show More