Merge pull request #2574 from acelaya-forks/phpunit-13

Update to PHPUnit 13
This commit is contained in:
Alejandro Celaya
2026-02-10 19:46:58 +01:00
committed by GitHub
12 changed files with 53 additions and 36 deletions

View File

@@ -4,6 +4,23 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com), and this project adheres to [Semantic Versioning](https://semver.org). The format is based on [Keep a Changelog](https://keepachangelog.com), and this project adheres to [Semantic Versioning](https://semver.org).
## [Unreleased]
### Added
* *Nothing*
### Changed
* [#2573](https://github.com/shlinkio/shlink/issues/2573) Update to PHPUnit 13
### Deprecated
* *Nothing*
### Removed
* *Nothing*
### Fixed
* *Nothing*
## [5.0.0] - 2026-01-09 ## [5.0.0] - 2026-01-09
### Added ### Added
* [#2431](https://github.com/shlinkio/shlink/issues/2431) Add new date-based conditions for the dynamic rules redirections system, that allow to perform redirections based on an ISO-8601 date value. * [#2431](https://github.com/shlinkio/shlink/issues/2431) Add new date-based conditions for the dynamic rules redirections system, that allow to perform redirections based on an ISO-8601 date value.

View File

@@ -41,12 +41,12 @@
"pagerfanta/core": "^3.8", "pagerfanta/core": "^3.8",
"ramsey/uuid": "^4.7", "ramsey/uuid": "^4.7",
"shlinkio/doctrine-specification": "^2.2", "shlinkio/doctrine-specification": "^2.2",
"shlinkio/shlink-common": "dev-main#d4ae052 as 8.0.0", "shlinkio/shlink-common": "^8.0.0",
"shlinkio/shlink-config": "dev-main#fb186e4 as 4.1.0", "shlinkio/shlink-config": "^4.1.0",
"shlinkio/shlink-event-dispatcher": "dev-main#54d4701 as 4.4.0", "shlinkio/shlink-event-dispatcher": "^4.4.0",
"shlinkio/shlink-importer": "dev-main#63753cf as 5.7.0", "shlinkio/shlink-importer": "^5.7.0",
"shlinkio/shlink-installer": "dev-develop#a225b16 as 10.0.0", "shlinkio/shlink-installer": "^10.0.0",
"shlinkio/shlink-ip-geolocation": "dev-main#e0c45b2 as 5.0.0", "shlinkio/shlink-ip-geolocation": "^5.0.0",
"shlinkio/shlink-json": "^1.3", "shlinkio/shlink-json": "^1.3",
"spiral/roadrunner": "^2025.1", "spiral/roadrunner": "^2025.1",
"spiral/roadrunner-cli": "^2.7", "spiral/roadrunner-cli": "^2.7",
@@ -65,17 +65,14 @@
"phpstan/phpstan-doctrine": "^2.0", "phpstan/phpstan-doctrine": "^2.0",
"phpstan/phpstan-phpunit": "^2.0.5", "phpstan/phpstan-phpunit": "^2.0.5",
"phpstan/phpstan-symfony": "^2.0", "phpstan/phpstan-symfony": "^2.0",
"phpunit/php-code-coverage": "^12.0", "phpunit/php-code-coverage": "^13.0",
"phpunit/phpcov": "^11.0", "phpunit/phpcov": "^12.0",
"phpunit/phpunit": "^12.0.10", "phpunit/phpunit": "^13.0",
"shlinkio/php-coding-standard": "~2.5.0", "shlinkio/php-coding-standard": "~2.5.0",
"shlinkio/shlink-test-utils": "^4.4", "shlinkio/shlink-test-utils": "^4.5",
"symfony/var-dumper": "^8.0", "symfony/var-dumper": "^8.0",
"veewee/composer-run-parallel": "^1.4" "veewee/composer-run-parallel": "^1.4"
}, },
"conflict": {
"symfony/var-exporter": ">=6.3.9,<=6.4.0"
},
"autoload": { "autoload": {
"psr-4": { "psr-4": {
"Shlinkio\\Shlink\\CLI\\": "module/CLI/src", "Shlinkio\\Shlink\\CLI\\": "module/CLI/src",

View File

@@ -50,7 +50,7 @@ class CreateShortUrlCommandTest extends TestCase
$this->urlShortener->expects($this->once())->method('shorten')->withAnyParameters()->willReturn( $this->urlShortener->expects($this->once())->method('shorten')->withAnyParameters()->willReturn(
UrlShorteningResult::withoutErrorOnEventDispatching($shortUrl), UrlShorteningResult::withoutErrorOnEventDispatching($shortUrl),
); );
$this->stringifier->method('stringify')->with($shortUrl)->willReturn('stringified_short_url'); $this->stringifier->method('stringify')->willReturnMap([[$shortUrl, 'stringified_short_url']]);
$this->commandTester->execute([ $this->commandTester->execute([
'long-url' => 'http://domain.com/foo/bar', 'long-url' => 'http://domain.com/foo/bar',
@@ -70,7 +70,7 @@ class CreateShortUrlCommandTest extends TestCase
$this->urlShortener->expects($this->once())->method('shorten')->withAnyParameters()->willReturn( $this->urlShortener->expects($this->once())->method('shorten')->withAnyParameters()->willReturn(
UrlShorteningResult::withoutErrorOnEventDispatching($shortUrl), UrlShorteningResult::withoutErrorOnEventDispatching($shortUrl),
); );
$this->stringifier->method('stringify')->with($shortUrl)->willReturn('stringified_short_url'); $this->stringifier->method('stringify')->willReturnMap([[$shortUrl, 'stringified_short_url']]);
$this->commandTester->setInputs([$shortUrl->getLongUrl()]); $this->commandTester->setInputs([$shortUrl->getLongUrl()]);
$this->commandTester->execute([]); $this->commandTester->execute([]);
@@ -101,7 +101,7 @@ class CreateShortUrlCommandTest extends TestCase
return true; return true;
}), }),
)->willReturn(UrlShorteningResult::withoutErrorOnEventDispatching($shortUrl)); )->willReturn(UrlShorteningResult::withoutErrorOnEventDispatching($shortUrl));
$this->stringifier->method('stringify')->with($shortUrl)->willReturn('stringified_short_url'); $this->stringifier->method('stringify')->willReturnMap([[$shortUrl, 'stringified_short_url']]);
$this->commandTester->execute([ $this->commandTester->execute([
'long-url' => 'http://domain.com/foo/bar', 'long-url' => 'http://domain.com/foo/bar',

View File

@@ -113,7 +113,7 @@ class RedirectRuleHandlerTest extends TestCase
array $expectedConditions, array $expectedConditions,
bool $continue = false, bool $continue = false,
): void { ): void {
$this->io->expects($this->any())->method('ask')->willReturnCallback( $this->io->method('ask')->willReturnCallback(
fn (string $message): string|int => match ($message) { fn (string $message): string|int => match ($message) {
'Rule priority (the lower the value, the higher the priority)' => 2, // Add in between existing rules 'Rule priority (the lower the value, the higher the priority)' => 2, // Add in between existing rules
'Long URL to redirect when the rule matches' => 'https://example.com/new-two', 'Long URL to redirect when the rule matches' => 'https://example.com/new-two',
@@ -127,7 +127,7 @@ class RedirectRuleHandlerTest extends TestCase
default => '', default => '',
}, },
); );
$this->io->expects($this->any())->method('choice')->willReturnCallback( $this->io->method('choice')->willReturnCallback(
function (string $message) use (&$callIndex, $type): string { function (string $message) use (&$callIndex, $type): string {
$callIndex++; $callIndex++;
@@ -241,7 +241,7 @@ class RedirectRuleHandlerTest extends TestCase
#[Test] #[Test]
public function existingRulesCanBeReArranged(): void public function existingRulesCanBeReArranged(): void
{ {
$this->io->expects($this->any())->method('ask')->willReturnCallback( $this->io->method('ask')->willReturnCallback(
fn (string $message): string|int => match ($message) { fn (string $message): string|int => match ($message) {
'Rule priority (the lower the value, the higher the priority)' => 1, 'Rule priority (the lower the value, the higher the priority)' => 1,
default => '', default => '',

View File

@@ -4,7 +4,6 @@ declare(strict_types=1);
namespace ShlinkioTest\Shlink\CLI\Util; namespace ShlinkioTest\Shlink\CLI\Util;
use PHPUnit\Framework\Assert;
use PHPUnit\Framework\MockObject\Generator\Generator; use PHPUnit\Framework\MockObject\Generator\Generator;
use PHPUnit\Framework\MockObject\Stub; use PHPUnit\Framework\MockObject\Stub;
use Symfony\Component\Console\Application; use Symfony\Component\Console\Application;
@@ -32,7 +31,6 @@ class CliTestUtils
$command->method('isEnabled')->willReturn(true); $command->method('isEnabled')->willReturn(true);
$command->method('getAliases')->willReturn([]); $command->method('getAliases')->willReturn([]);
$command->method('getDefinition')->willReturn(new InputDefinition()); $command->method('getDefinition')->willReturn(new InputDefinition());
$command->method('setApplication')->with(Assert::isInstanceOf(Application::class));
return $command; return $command;
} }

View File

@@ -111,7 +111,7 @@ class DomainServiceTest extends TestCase
#[Test, AllowMockObjectsWithoutExpectations] #[Test, AllowMockObjectsWithoutExpectations]
public function getDomainThrowsExceptionWhenDomainIsNotFound(): void public function getDomainThrowsExceptionWhenDomainIsNotFound(): void
{ {
$this->em->method('find')->with(Domain::class, '123')->willReturn(null); $this->em->method('find')->willReturnMap([[Domain::class, '123', null]]);
$this->expectException(DomainNotFoundException::class); $this->expectException(DomainNotFoundException::class);
@@ -122,7 +122,7 @@ class DomainServiceTest extends TestCase
public function getDomainReturnsEntityWhenFound(): void public function getDomainReturnsEntityWhenFound(): void
{ {
$domain = Domain::withAuthority(''); $domain = Domain::withAuthority('');
$this->em->method('find')->with(Domain::class, '123')->willReturn($domain); $this->em->method('find')->willReturnMap([[Domain::class, '123', $domain]]);
$result = $this->domainService->getDomain('123'); $result = $this->domainService->getDomain('123');
@@ -136,7 +136,6 @@ class DomainServiceTest extends TestCase
$this->repo->expects($this->once())->method('findOneByAuthority')->with($authority, $apiKey)->willReturn( $this->repo->expects($this->once())->method('findOneByAuthority')->with($authority, $apiKey)->willReturn(
$foundDomain, $foundDomain,
); );
$this->em->method('persist')->with($foundDomain ?? $this->isInstanceOf(Domain::class));
$result = $this->domainService->getOrCreate($authority, $apiKey); $result = $this->domainService->getOrCreate($authority, $apiKey);
@@ -168,7 +167,6 @@ class DomainServiceTest extends TestCase
$this->repo->expects($this->once())->method('findOneByAuthority')->with($authority, $apiKey)->willReturn( $this->repo->expects($this->once())->method('findOneByAuthority')->with($authority, $apiKey)->willReturn(
$foundDomain, $foundDomain,
); );
$this->em->method('persist')->with($foundDomain ?? $this->isInstanceOf(Domain::class));
$result = $this->domainService->configureNotFoundRedirects($authority, NotFoundRedirects::withRedirects( $result = $this->domainService->configureNotFoundRedirects($authority, NotFoundRedirects::withRedirects(
'foo.com', 'foo.com',

View File

@@ -229,7 +229,7 @@ class ImportedLinksProcessorTest extends TestCase
$this->em->expects($this->exactly($amountOfPersistedVisits + ($foundShortUrl === null ? 1 : 0)))->method( $this->em->expects($this->exactly($amountOfPersistedVisits + ($foundShortUrl === null ? 1 : 0)))->method(
'persist', 'persist',
)->with($this->callback(fn (object $arg) => $arg instanceof ShortUrl || $arg instanceof Visit)); )->with($this->callback(fn (object $arg) => $arg instanceof ShortUrl || $arg instanceof Visit));
$this->em->expects($this->any())->method('find')->willReturn(null); $this->em->method('find')->willReturn(null);
$this->io->expects($this->once())->method('text')->with($this->stringContains($expectedOutput)); $this->io->expects($this->once())->method('text')->with($this->stringContains($expectedOutput));
$this->processor->process($this->io, ImportResult::withShortUrls([$importedUrl]), $this->buildParams()); $this->processor->process($this->io, ImportResult::withShortUrls([$importedUrl]), $this->buildParams());

View File

@@ -116,15 +116,12 @@ class MatomoVisitSenderTest extends TestCase
#[Test, DataProvider('provideUrlsToTrack')] #[Test, DataProvider('provideUrlsToTrack')]
public function properUrlIsTracked(Visit $visit, string $expectedTrackedUrl): void public function properUrlIsTracked(Visit $visit, string $expectedTrackedUrl): void
{ {
$tracker = $this->createMock(MatomoTracker::class); $tracker = $this->createStub(MatomoTracker::class);
$tracker->expects($this->once())->method('setUrl')->with($expectedTrackedUrl)->willReturn($tracker); $tracker->method('setUrl')->willReturn($tracker);
$tracker->expects($this->once())->method('setUserAgent')->willReturn($tracker); $tracker->method('setUserAgent')->willReturn($tracker);
$tracker->expects($this->once())->method('setUrlReferrer')->willReturn($tracker); $tracker->method('setUrlReferrer')->willReturn($tracker);
$tracker->expects($this->any())->method('setCustomTrackingParameter')->willReturn($tracker); $tracker->method('setCustomTrackingParameter')->willReturn($tracker);
$tracker->expects($this->once())->method('doTrackPageView'); $tracker->method('doTrackPageView');
$tracker->expects($this->once())->method('setForceVisitDateTime')->with(
$visit->date->setTimezone('UTC')->toDateTimeString(),
);
$this->trackerBuilder->expects($this->once())->method('buildMatomoTracker')->willReturn($tracker); $this->trackerBuilder->expects($this->once())->method('buildMatomoTracker')->willReturn($tracker);
@@ -156,7 +153,7 @@ class MatomoVisitSenderTest extends TestCase
$visitor = Visitor::empty(); $visitor = Visitor::empty();
$bot = Visitor::botInstance(); $bot = Visitor::botInstance();
$this->visitIterationRepository->method('findAllVisits')->with($dateRange)->willReturn([ $this->visitIterationRepository->method('findAllVisits')->willReturn([
Visit::forBasePath($bot), Visit::forBasePath($bot),
Visit::forValidShortUrl(ShortUrl::createFake(), $visitor), Visit::forValidShortUrl(ShortUrl::createFake(), $visitor),
Visit::forInvalidShortUrl($visitor), Visit::forInvalidShortUrl($visitor),

View File

@@ -7,6 +7,9 @@
cacheDirectory="build/.phpunit/api-tests.cache" cacheDirectory="build/.phpunit/api-tests.cache"
displayDetailsOnTestsThatTriggerWarnings="true" displayDetailsOnTestsThatTriggerWarnings="true"
displayDetailsOnTestsThatTriggerDeprecations="true" displayDetailsOnTestsThatTriggerDeprecations="true"
displayDetailsOnPhpunitNotices="true"
displayDetailsOnPhpunitDeprecations="true"
displayDetailsOnTestsThatTriggerNotices="true"
> >
<testsuites> <testsuites>
<testsuite name="Shlink API tests"> <testsuite name="Shlink API tests">

View File

@@ -7,6 +7,9 @@
cacheDirectory="build/.phpunit/cli-tests.cache" cacheDirectory="build/.phpunit/cli-tests.cache"
displayDetailsOnTestsThatTriggerWarnings="true" displayDetailsOnTestsThatTriggerWarnings="true"
displayDetailsOnTestsThatTriggerDeprecations="true" displayDetailsOnTestsThatTriggerDeprecations="true"
displayDetailsOnPhpunitNotices="true"
displayDetailsOnPhpunitDeprecations="true"
displayDetailsOnTestsThatTriggerNotices="true"
> >
<testsuites> <testsuites>
<testsuite name="Shlink CLI tests"> <testsuite name="Shlink CLI tests">

View File

@@ -7,6 +7,9 @@
cacheDirectory="build/.phpunit/db-tests.cache" cacheDirectory="build/.phpunit/db-tests.cache"
displayDetailsOnTestsThatTriggerWarnings="true" displayDetailsOnTestsThatTriggerWarnings="true"
displayDetailsOnTestsThatTriggerDeprecations="true" displayDetailsOnTestsThatTriggerDeprecations="true"
displayDetailsOnPhpunitNotices="true"
displayDetailsOnPhpunitDeprecations="true"
displayDetailsOnTestsThatTriggerNotices="true"
> >
<testsuites> <testsuites>
<testsuite name="Shlink database tests"> <testsuite name="Shlink database tests">

View File

@@ -8,6 +8,7 @@
displayDetailsOnTestsThatTriggerWarnings="true" displayDetailsOnTestsThatTriggerWarnings="true"
displayDetailsOnTestsThatTriggerDeprecations="true" displayDetailsOnTestsThatTriggerDeprecations="true"
displayDetailsOnPhpunitNotices="true" displayDetailsOnPhpunitNotices="true"
displayDetailsOnPhpunitDeprecations="true"
displayDetailsOnTestsThatTriggerNotices="true" displayDetailsOnTestsThatTriggerNotices="true"
> >
<testsuites> <testsuites>