Merge pull request #2533 from acelaya-forks/improve-coverage-2

Add more code coverage improvements
This commit is contained in:
Alejandro Celaya
2025-11-18 09:33:20 +01:00
committed by GitHub
11 changed files with 149 additions and 23 deletions

View File

@@ -91,11 +91,17 @@ class RoleResolverTest extends TestCase
[RoleDefinition::forAuthoredShortUrls()],
0,
];
yield 'both roles' => [
$buildInput(
[Role::DOMAIN_SPECIFIC->paramName() => 'example.com', Role::AUTHORED_SHORT_URLS->paramName() => true],
),
[RoleDefinition::forAuthoredShortUrls(), RoleDefinition::forDomain($domain)],
yield 'all roles' => [
$buildInput([
Role::DOMAIN_SPECIFIC->paramName() => 'example.com',
Role::AUTHORED_SHORT_URLS->paramName() => true,
Role::NO_ORPHAN_VISITS->paramName() => true,
]),
[
RoleDefinition::forAuthoredShortUrls(),
RoleDefinition::forDomain($domain),
RoleDefinition::forNoOrphanVisits(),
],
1,
];
}

View File

@@ -64,6 +64,21 @@ class CreateShortUrlCommandTest extends TestCase
self::assertStringNotContainsString('but the real-time updates cannot', $output);
}
#[Test]
public function longUrlIsAskedIfNotProvided(): void
{
$shortUrl = ShortUrl::createFake();
$this->urlShortener->expects($this->once())->method('shorten')->withAnyParameters()->willReturn(
UrlShorteningResult::withoutErrorOnEventDispatching($shortUrl),
);
$this->stringifier->expects($this->once())->method('stringify')->with($shortUrl)->willReturn(
'stringified_short_url',
);
$this->commandTester->setInputs([$shortUrl->getLongUrl()]);
$this->commandTester->execute([]);
}
#[Test]
public function providingNonUniqueSlugOutputsError(): void
{

View File

@@ -50,6 +50,19 @@ class GetShortUrlVisitsCommandTest extends TestCase
$this->commandTester->execute(['shortCode' => $shortCode]);
}
#[Test]
public function shortCodeIsAskedIfNotProvided(): void
{
$shortCode = 'abc123';
$this->visitsHelper->expects($this->once())->method('visitsForShortUrl')->with(
ShortUrlIdentifier::fromShortCodeAndDomain($shortCode),
$this->anything(),
)->willReturn(new Paginator(new ArrayAdapter([])));
$this->commandTester->setInputs([$shortCode]);
$this->commandTester->execute([]);
}
#[Test]
public function providingDateFlagsTheListGetsFiltered(): void
{

View File

@@ -45,6 +45,19 @@ class ResolveUrlCommandTest extends TestCase
self::assertEquals('Long URL: ' . $expectedUrl . PHP_EOL, $output);
}
#[Test]
public function shortCodeIsAskedIfNotProvided(): void
{
$shortCode = 'abc123';
$shortUrl = ShortUrl::createFake();
$this->urlResolver->expects($this->once())->method('resolveShortUrl')->with(
ShortUrlIdentifier::fromShortCodeAndDomain($shortCode),
)->willReturn($shortUrl);
$this->commandTester->setInputs([$shortCode]);
$this->commandTester->execute([]);
}
#[Test]
public function incorrectShortCodeOutputsErrorMessage(): void
{

View File

@@ -6,8 +6,6 @@ namespace Shlinkio\Shlink\Core\Config\Options;
use Shlinkio\Shlink\Core\Config\EnvVars;
use function sprintf;
final class AppOptions
{
public function __construct(public string $name = 'Shlink', public string $version = '4.0.0')
@@ -19,9 +17,4 @@ final class AppOptions
$version = EnvVars::isDevEnv() ? 'latest' : '%SHLINK_VERSION%';
return new self(version: $version);
}
public function __toString(): string
{
return sprintf('%s:v%s', $this->name, $this->version);
}
}

View File

@@ -15,9 +15,7 @@ final readonly class ShortUrlCreated implements JsonSerializable, JsonUnserializ
public function jsonSerialize(): array
{
return [
'shortUrlId' => $this->shortUrlId,
];
return ['shortUrlId' => $this->shortUrlId];
}
public static function fromPayload(array $payload): self

View File

@@ -15,7 +15,7 @@ use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\UriInterface;
use Psr\Log\NullLogger;
use Psr\Log\LoggerInterface;
use Shlinkio\Shlink\Core\Action\RedirectAction;
use Shlinkio\Shlink\Core\Config\NotFoundRedirectResolver;
use Shlinkio\Shlink\Core\Config\Options\NotFoundRedirectOptions;
@@ -28,11 +28,14 @@ class NotFoundRedirectResolverTest extends TestCase
{
private NotFoundRedirectResolver $resolver;
private MockObject & RedirectResponseHelperInterface $helper;
private MockObject & LoggerInterface $logger;
protected function setUp(): void
{
$this->helper = $this->createMock(RedirectResponseHelperInterface::class);
$this->resolver = new NotFoundRedirectResolver($this->helper, new NullLogger());
$this->logger = $this->createMock(LoggerInterface::class);
$this->resolver = new NotFoundRedirectResolver($this->helper, $this->logger);
}
#[Test, DataProvider('provideRedirects')]
@@ -123,6 +126,22 @@ class NotFoundRedirectResolverTest extends TestCase
self::assertNull($result);
}
#[Test]
public function warningMessageIsLoggedIfRedirectUrlIsMalformed(): void
{
$this->logger->expects($this->once())->method('warning')->with(
'It was not possible to parse "{url}" as a valid URL: {e}',
$this->isArray(),
);
$uri = new Uri('/');
$this->resolver->resolveRedirectResponse(
self::notFoundType(ServerRequestFactory::fromGlobals()->withUri($uri)),
new NotFoundRedirectOptions(baseUrlRedirect: 'http:///example.com'),
$uri,
);
}
private static function notFoundType(ServerRequestInterface $req): NotFoundType
{
return NotFoundType::fromRequest($req, '');

View File

@@ -0,0 +1,29 @@
<?php
declare(strict_types=1);
namespace ShlinkioTest\Shlink\Core\EventDispatcher\Event;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\Attributes\TestWith;
use PHPUnit\Framework\TestCase;
use Shlinkio\Shlink\Core\EventDispatcher\Event\ShortUrlCreated;
class ShortUrlCreatedTest extends TestCase
{
#[Test]
public function jsonSerialization(): void
{
$shortUrlId = 'abc123';
self::assertEquals(['shortUrlId' => $shortUrlId], new ShortUrlCreated($shortUrlId)->jsonSerialize());
}
#[Test]
#[TestWith([['shortUrlId' => '123'], '123'])]
#[TestWith([[], ''])]
public function creationFromPayload(array $payload, string $expectedShortUrlId): void
{
$event = ShortUrlCreated::fromPayload($payload);
self::assertEquals($expectedShortUrlId, $event->shortUrlId);
}
}

View File

@@ -0,0 +1,35 @@
<?php
declare(strict_types=1);
namespace ShlinkioTest\Shlink\Core\EventDispatcher\Event;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\Attributes\TestWith;
use PHPUnit\Framework\TestCase;
use Shlinkio\Shlink\Core\EventDispatcher\Event\UrlVisited;
class UrlVisitedTest extends TestCase
{
#[Test]
public function jsonSerialization(): void
{
$visitId = 'abc123';
self::assertEquals(
['visitId' => $visitId, 'originalIpAddress' => null],
new UrlVisited($visitId)->jsonSerialize(),
);
}
#[Test]
#[TestWith([['visitId' => '123', 'originalIpAddress' => '1.2.3.4'], '123', '1.2.3.4'])]
#[TestWith([['visitId' => '123'], '123', null])]
#[TestWith([['originalIpAddress' => '1.2.3.4'], '', '1.2.3.4'])]
#[TestWith([[], '', null])]
public function creationFromPayload(array $payload, string $expectedVisitId, string|null $expectedIpAddress): void
{
$event = UrlVisited::fromPayload($payload);
self::assertEquals($expectedVisitId, $event->visitId);
self::assertEquals($expectedIpAddress, $event->originalIpAddress);
}
}

View File

@@ -12,10 +12,4 @@ class ApiKeyNotFoundException extends RuntimeException implements ExceptionInter
{
return new self(sprintf('API key with name "%s" not found', $name));
}
/** @deprecated */
public static function forKey(string $key): self
{
return new self(sprintf('API key with key "%s" not found', $key));
}
}

View File

@@ -77,4 +77,15 @@ class MercureInfoActionTest extends TestCase
yield 'days not defined' => [null];
yield 'days defined' => [10];
}
#[Test]
public function getRouteDefReturnsExpectedData(): void
{
self::assertEquals([
'name' => MercureInfoAction::class,
'middleware' => [MercureInfoAction::class],
'path' => '/mercure-info',
'allowed_methods' => ['GET'],
], MercureInfoAction::getRouteDef());
}
}