Merge pull request #1585 from acelaya-forks/feature/phpunit-mocks

Feature/phpunit mocks
This commit is contained in:
Alejandro Celaya 2022-10-23 20:19:22 +02:00 committed by GitHub
commit 7ceae7af87
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
53 changed files with 475 additions and 674 deletions

View file

@ -14,7 +14,6 @@ jobs:
strategy: strategy:
matrix: matrix:
php-version: ['8.1', '8.2'] php-version: ['8.1', '8.2']
continue-on-error: ${{ matrix.php-version == '8.2' }}
env: env:
LC_ALL: C LC_ALL: C
steps: steps:

View file

@ -14,7 +14,6 @@ jobs:
strategy: strategy:
matrix: matrix:
php-version: ['8.1', '8.2'] php-version: ['8.1', '8.2']
continue-on-error: ${{ matrix.php-version == '8.2' }}
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- uses: './.github/actions/ci-setup' - uses: './.github/actions/ci-setup'

View file

@ -14,7 +14,6 @@ jobs:
strategy: strategy:
matrix: matrix:
php-version: ['8.1', '8.2'] php-version: ['8.1', '8.2']
continue-on-error: ${{ matrix.php-version == '8.2' }}
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: Start postgres database server - name: Start postgres database server

View file

@ -44,7 +44,6 @@ jobs:
strategy: strategy:
matrix: matrix:
php-version: ['8.1', '8.2'] php-version: ['8.1', '8.2']
continue-on-error: ${{ matrix.php-version == '8.2' }}
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- run: docker-compose -f docker-compose.yml -f docker-compose.ci.yml up -d shlink_db_postgres - run: docker-compose -f docker-compose.yml -f docker-compose.ci.yml up -d shlink_db_postgres

View file

@ -36,11 +36,9 @@ class RoleResolverTest extends TestCase
array $expectedRoles, array $expectedRoles,
int $expectedDomainCalls, int $expectedDomainCalls,
): void { ): void {
$this->domainService $this->domainService->expects($this->exactly($expectedDomainCalls))->method('getOrCreate')->with(
->expects($this->exactly($expectedDomainCalls)) 'example.com',
->method('getOrCreate') )->willReturn(Domain::withAuthority('example.com')->setId('1'));
->with($this->equalTo('example.com'))
->willReturn(Domain::withAuthority('example.com')->setId('1'));
$result = $this->resolver->determineRoles($input); $result = $this->resolver->determineRoles($input);

View file

@ -29,7 +29,7 @@ class DisableKeyCommandTest extends TestCase
public function providedApiKeyIsDisabled(): void public function providedApiKeyIsDisabled(): void
{ {
$apiKey = 'abcd1234'; $apiKey = 'abcd1234';
$this->apiKeyService->expects($this->once())->method('disable')->with($this->equalTo($apiKey)); $this->apiKeyService->expects($this->once())->method('disable')->with($apiKey);
$this->commandTester->execute([ $this->commandTester->execute([
'apiKey' => $apiKey, 'apiKey' => $apiKey,
@ -44,9 +44,9 @@ class DisableKeyCommandTest extends TestCase
{ {
$apiKey = 'abcd1234'; $apiKey = 'abcd1234';
$expectedMessage = 'API key "abcd1234" does not exist.'; $expectedMessage = 'API key "abcd1234" does not exist.';
$this->apiKeyService->expects($this->once())->method('disable')->with( $this->apiKeyService->expects($this->once())->method('disable')->with($apiKey)->willThrowException(
$this->equalTo($apiKey), new InvalidArgumentException($expectedMessage),
)->willThrowException(new InvalidArgumentException($expectedMessage)); );
$this->commandTester->execute([ $this->commandTester->execute([
'apiKey' => $apiKey, 'apiKey' => $apiKey,

View file

@ -35,9 +35,7 @@ class ListKeysCommandTest extends TestCase
*/ */
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( $this->apiKeyService->expects($this->once())->method('listKeys')->with($enabledOnly)->willReturn($keys);
$this->equalTo($enabledOnly),
)->willReturn($keys);
$this->commandTester->execute(['--enabled-only' => $enabledOnly]); $this->commandTester->execute(['--enabled-only' => $enabledOnly]);
$output = $this->commandTester->getDisplay(); $output = $this->commandTester->getDisplay();

View file

@ -87,7 +87,7 @@ class CreateDatabaseCommandTest extends TestCase
$shlinkDatabase = 'shlink_database'; $shlinkDatabase = 'shlink_database';
$this->regularConn->expects($this->once())->method('getParams')->willReturn(['dbname' => $shlinkDatabase]); $this->regularConn->expects($this->once())->method('getParams')->willReturn(['dbname' => $shlinkDatabase]);
$this->schemaManager->expects($this->once())->method('listDatabases')->willReturn(['foo', 'bar']); $this->schemaManager->expects($this->once())->method('listDatabases')->willReturn(['foo', 'bar']);
$this->schemaManager->expects($this->once())->method('createDatabase')->with($this->equalTo($shlinkDatabase)); $this->schemaManager->expects($this->once())->method('createDatabase')->with($shlinkDatabase);
$this->schemaManager->expects($this->once())->method('listTableNames')->willReturn( $this->schemaManager->expects($this->once())->method('listTableNames')->willReturn(
['foo_table', 'bar_table', MIGRATIONS_TABLE], ['foo_table', 'bar_table', MIGRATIONS_TABLE],
); );
@ -109,15 +109,12 @@ class CreateDatabaseCommandTest extends TestCase
); );
$this->schemaManager->expects($this->never())->method('createDatabase'); $this->schemaManager->expects($this->never())->method('createDatabase');
$this->schemaManager->expects($this->once())->method('listTableNames')->willReturn($tables); $this->schemaManager->expects($this->once())->method('listTableNames')->willReturn($tables);
$this->processHelper->expects($this->once())->method('run')->with( $this->processHelper->expects($this->once())->method('run')->with($this->isInstanceOf(OutputInterface::class), [
$this->isInstanceOf(OutputInterface::class), '/usr/local/bin/php',
$this->equalTo([ CreateDatabaseCommand::DOCTRINE_SCRIPT,
'/usr/local/bin/php', CreateDatabaseCommand::DOCTRINE_CREATE_SCHEMA_COMMAND,
CreateDatabaseCommand::DOCTRINE_SCRIPT, '--no-interaction',
CreateDatabaseCommand::DOCTRINE_CREATE_SCHEMA_COMMAND, ]);
'--no-interaction',
]),
);
$this->driver->method('getDatabasePlatform')->willReturn($this->createMock(AbstractPlatform::class)); $this->driver->method('getDatabasePlatform')->willReturn($this->createMock(AbstractPlatform::class));
$this->commandTester->execute([]); $this->commandTester->execute([]);

View file

@ -41,15 +41,12 @@ class MigrateDatabaseCommandTest extends TestCase
/** @test */ /** @test */
public function migrationsCommandIsRunWithProperVerbosity(): void public function migrationsCommandIsRunWithProperVerbosity(): void
{ {
$this->processHelper->expects($this->once())->method('run')->with( $this->processHelper->expects($this->once())->method('run')->with($this->isInstanceOf(OutputInterface::class), [
$this->isInstanceOf(OutputInterface::class), '/usr/local/bin/php',
$this->equalTo([ MigrateDatabaseCommand::DOCTRINE_MIGRATIONS_SCRIPT,
'/usr/local/bin/php', MigrateDatabaseCommand::DOCTRINE_MIGRATE_COMMAND,
MigrateDatabaseCommand::DOCTRINE_MIGRATIONS_SCRIPT, '--no-interaction',
MigrateDatabaseCommand::DOCTRINE_MIGRATE_COMMAND, ]);
'--no-interaction',
]),
);
$this->commandTester->execute([]); $this->commandTester->execute([]);
$output = $this->commandTester->getDisplay(); $output = $this->commandTester->getDisplay();

View file

@ -37,12 +37,12 @@ class DomainRedirectsCommandTest extends TestCase
public function onlyPlainQuestionsAreAskedForNewDomainsAndDomainsWithNoRedirects(?Domain $domain): void public function onlyPlainQuestionsAreAskedForNewDomainsAndDomainsWithNoRedirects(?Domain $domain): void
{ {
$domainAuthority = 'my-domain.com'; $domainAuthority = 'my-domain.com';
$this->domainService->expects($this->once())->method('findByAuthority')->with( $this->domainService->expects($this->once())->method('findByAuthority')->with($domainAuthority)->willReturn(
$this->equalTo($domainAuthority), $domain,
)->willReturn($domain); );
$this->domainService->expects($this->once())->method('configureNotFoundRedirects')->with( $this->domainService->expects($this->once())->method('configureNotFoundRedirects')->with(
$this->equalTo($domainAuthority), $domainAuthority,
$this->equalTo(NotFoundRedirects::withRedirects('foo.com', null, 'baz.com')), NotFoundRedirects::withRedirects('foo.com', null, 'baz.com'),
)->willReturn(Domain::withAuthority('')); )->willReturn(Domain::withAuthority(''));
$this->domainService->expects($this->never())->method('listDomains'); $this->domainService->expects($this->never())->method('listDomains');
@ -73,12 +73,12 @@ class DomainRedirectsCommandTest extends TestCase
$domain = Domain::withAuthority($domainAuthority); $domain = Domain::withAuthority($domainAuthority);
$domain->configureNotFoundRedirects(NotFoundRedirects::withRedirects('foo.com', 'bar.com', 'baz.com')); $domain->configureNotFoundRedirects(NotFoundRedirects::withRedirects('foo.com', 'bar.com', 'baz.com'));
$this->domainService->expects($this->once())->method('findByAuthority')->with( $this->domainService->expects($this->once())->method('findByAuthority')->with($domainAuthority)->willReturn(
$this->equalTo($domainAuthority), $domain,
)->willReturn($domain); );
$this->domainService->expects($this->once())->method('configureNotFoundRedirects')->with( $this->domainService->expects($this->once())->method('configureNotFoundRedirects')->with(
$this->equalTo($domainAuthority), $domainAuthority,
$this->equalTo(NotFoundRedirects::withRedirects(null, 'edited.com', 'baz.com')), NotFoundRedirects::withRedirects(null, 'edited.com', 'baz.com'),
)->willReturn($domain); )->willReturn($domain);
$this->domainService->expects($this->never())->method('listDomains'); $this->domainService->expects($this->never())->method('listDomains');
@ -102,12 +102,12 @@ class DomainRedirectsCommandTest extends TestCase
$domain = Domain::withAuthority($domainAuthority); $domain = Domain::withAuthority($domainAuthority);
$this->domainService->expects($this->once())->method('listDomains')->with()->willReturn([]); $this->domainService->expects($this->once())->method('listDomains')->with()->willReturn([]);
$this->domainService->expects($this->once())->method('findByAuthority')->with( $this->domainService->expects($this->once())->method('findByAuthority')->with($domainAuthority)->willReturn(
$this->equalTo($domainAuthority), $domain,
)->willReturn($domain); );
$this->domainService->expects($this->once())->method('configureNotFoundRedirects')->with( $this->domainService->expects($this->once())->method('configureNotFoundRedirects')->with(
$this->equalTo($domainAuthority), $domainAuthority,
$this->equalTo(NotFoundRedirects::withoutRedirects()), NotFoundRedirects::withoutRedirects(),
)->willReturn($domain); )->willReturn($domain);
$this->commandTester->setInputs([$domainAuthority, '', '', '']); $this->commandTester->setInputs([$domainAuthority, '', '', '']);
@ -128,12 +128,12 @@ class DomainRedirectsCommandTest extends TestCase
DomainItem::forNonDefaultDomain(Domain::withAuthority('existing-one.com')), DomainItem::forNonDefaultDomain(Domain::withAuthority('existing-one.com')),
DomainItem::forNonDefaultDomain(Domain::withAuthority($domainAuthority)), DomainItem::forNonDefaultDomain(Domain::withAuthority($domainAuthority)),
]); ]);
$this->domainService->expects($this->once())->method('findByAuthority')->with( $this->domainService->expects($this->once())->method('findByAuthority')->with($domainAuthority)->willReturn(
$this->equalTo($domainAuthority), $domain,
)->willReturn($domain); );
$this->domainService->expects($this->once())->method('configureNotFoundRedirects')->with( $this->domainService->expects($this->once())->method('configureNotFoundRedirects')->with(
$this->equalTo($domainAuthority), $domainAuthority,
$this->equalTo(NotFoundRedirects::withoutRedirects()), NotFoundRedirects::withoutRedirects(),
)->willReturn($domain); )->willReturn($domain);
$this->commandTester->setInputs(['1', '', '', '']); $this->commandTester->setInputs(['1', '', '', '']);
@ -157,12 +157,12 @@ class DomainRedirectsCommandTest extends TestCase
DomainItem::forNonDefaultDomain(Domain::withAuthority('existing-one.com')), DomainItem::forNonDefaultDomain(Domain::withAuthority('existing-one.com')),
DomainItem::forNonDefaultDomain(Domain::withAuthority('existing-two.com')), DomainItem::forNonDefaultDomain(Domain::withAuthority('existing-two.com')),
]); ]);
$this->domainService->expects($this->once())->method('findByAuthority')->with( $this->domainService->expects($this->once())->method('findByAuthority')->with($domainAuthority)->willReturn(
$this->equalTo($domainAuthority), $domain,
)->willReturn($domain); );
$this->domainService->expects($this->once())->method('configureNotFoundRedirects')->with( $this->domainService->expects($this->once())->method('configureNotFoundRedirects')->with(
$this->equalTo($domainAuthority), $domainAuthority,
$this->equalTo(NotFoundRedirects::withoutRedirects()), NotFoundRedirects::withoutRedirects(),
)->willReturn($domain); )->willReturn($domain);
$this->commandTester->setInputs(['2', $domainAuthority, '', '', '']); $this->commandTester->setInputs(['2', $domainAuthority, '', '', '']);

View file

@ -46,10 +46,10 @@ class GetDomainVisitsCommandTest extends TestCase
); );
$domain = 'doma.in'; $domain = 'doma.in';
$this->visitsHelper->expects($this->once())->method('visitsForDomain')->with( $this->visitsHelper->expects($this->once())->method('visitsForDomain')->with(
$this->equalTo($domain), $domain,
$this->anything(), $this->anything(),
)->willReturn(new Paginator(new ArrayAdapter([$visit]))); )->willReturn(new Paginator(new ArrayAdapter([$visit])));
$this->stringifier->expects($this->once())->method('stringify')->with($this->equalTo($shortUrl))->willReturn( $this->stringifier->expects($this->once())->method('stringify')->with($shortUrl)->willReturn(
'the_short_url', 'the_short_url',
); );

View file

@ -47,7 +47,7 @@ class CreateShortUrlCommandTest extends TestCase
{ {
$shortUrl = ShortUrl::createEmpty(); $shortUrl = ShortUrl::createEmpty();
$this->urlShortener->expects($this->once())->method('shorten')->withAnyParameters()->willReturn($shortUrl); $this->urlShortener->expects($this->once())->method('shorten')->withAnyParameters()->willReturn($shortUrl);
$this->stringifier->expects($this->once())->method('stringify')->with($this->equalTo($shortUrl))->willReturn( $this->stringifier->expects($this->once())->method('stringify')->with($shortUrl)->willReturn(
'stringified_short_url', 'stringified_short_url',
); );
@ -103,7 +103,7 @@ class CreateShortUrlCommandTest extends TestCase
return true; return true;
}), }),
)->willReturn($shortUrl); )->willReturn($shortUrl);
$this->stringifier->expects($this->once())->method('stringify')->with($this->equalTo($shortUrl))->willReturn( $this->stringifier->expects($this->once())->method('stringify')->with($shortUrl)->willReturn(
'stringified_short_url', 'stringified_short_url',
); );

View file

@ -35,7 +35,7 @@ class DeleteShortUrlCommandTest extends TestCase
{ {
$shortCode = 'abc123'; $shortCode = 'abc123';
$this->service->expects($this->once())->method('deleteByShortCode')->with( $this->service->expects($this->once())->method('deleteByShortCode')->with(
$this->equalTo(ShortUrlIdentifier::fromShortCodeAndDomain($shortCode)), ShortUrlIdentifier::fromShortCodeAndDomain($shortCode),
$this->isFalse(), $this->isFalse(),
); );
@ -54,7 +54,7 @@ class DeleteShortUrlCommandTest extends TestCase
$shortCode = 'abc123'; $shortCode = 'abc123';
$identifier = ShortUrlIdentifier::fromShortCodeAndDomain($shortCode); $identifier = ShortUrlIdentifier::fromShortCodeAndDomain($shortCode);
$this->service->expects($this->once())->method('deleteByShortCode')->with( $this->service->expects($this->once())->method('deleteByShortCode')->with(
$this->equalTo($identifier), $identifier,
$this->isFalse(), $this->isFalse(),
)->willThrowException(Exception\ShortUrlNotFoundException::fromNotFound($identifier)); )->willThrowException(Exception\ShortUrlNotFoundException::fromNotFound($identifier));
@ -76,7 +76,7 @@ class DeleteShortUrlCommandTest extends TestCase
$shortCode = 'abc123'; $shortCode = 'abc123';
$identifier = ShortUrlIdentifier::fromShortCodeAndDomain($shortCode); $identifier = ShortUrlIdentifier::fromShortCodeAndDomain($shortCode);
$this->service->expects($this->exactly($expectedDeleteCalls))->method('deleteByShortCode')->with( $this->service->expects($this->exactly($expectedDeleteCalls))->method('deleteByShortCode')->with(
$this->equalTo($identifier), $identifier,
$this->isType('bool'), $this->isType('bool'),
)->willReturnCallback(function ($_, bool $ignoreThreshold) use ($shortCode): void { )->willReturnCallback(function ($_, bool $ignoreThreshold) use ($shortCode): void {
if (!$ignoreThreshold) { if (!$ignoreThreshold) {
@ -110,7 +110,7 @@ class DeleteShortUrlCommandTest extends TestCase
{ {
$shortCode = 'abc123'; $shortCode = 'abc123';
$this->service->expects($this->once())->method('deleteByShortCode')->with( $this->service->expects($this->once())->method('deleteByShortCode')->with(
$this->equalTo(ShortUrlIdentifier::fromShortCodeAndDomain($shortCode)), ShortUrlIdentifier::fromShortCodeAndDomain($shortCode),
$this->isFalse(), $this->isFalse(),
)->willThrowException(Exception\DeleteShortUrlException::fromVisitsThreshold( )->willThrowException(Exception\DeleteShortUrlException::fromVisitsThreshold(
10, 10,

View file

@ -44,8 +44,8 @@ class GetShortUrlVisitsCommandTest extends TestCase
{ {
$shortCode = 'abc123'; $shortCode = 'abc123';
$this->visitsHelper->expects($this->once())->method('visitsForShortUrl')->with( $this->visitsHelper->expects($this->once())->method('visitsForShortUrl')->with(
$this->equalTo(ShortUrlIdentifier::fromShortCodeAndDomain($shortCode)), ShortUrlIdentifier::fromShortCodeAndDomain($shortCode),
$this->equalTo(new VisitsParams(DateRange::allTime())), new VisitsParams(DateRange::allTime()),
)->willReturn(new Paginator(new ArrayAdapter([]))); )->willReturn(new Paginator(new ArrayAdapter([])));
$this->commandTester->execute(['shortCode' => $shortCode]); $this->commandTester->execute(['shortCode' => $shortCode]);
@ -58,8 +58,8 @@ class GetShortUrlVisitsCommandTest extends TestCase
$startDate = '2016-01-01'; $startDate = '2016-01-01';
$endDate = '2016-02-01'; $endDate = '2016-02-01';
$this->visitsHelper->expects($this->once())->method('visitsForShortUrl')->with( $this->visitsHelper->expects($this->once())->method('visitsForShortUrl')->with(
$this->equalTo(ShortUrlIdentifier::fromShortCodeAndDomain($shortCode)), ShortUrlIdentifier::fromShortCodeAndDomain($shortCode),
$this->equalTo(new VisitsParams(buildDateRange(Chronos::parse($startDate), Chronos::parse($endDate)))), new VisitsParams(buildDateRange(Chronos::parse($startDate), Chronos::parse($endDate))),
)->willReturn(new Paginator(new ArrayAdapter([]))); )->willReturn(new Paginator(new ArrayAdapter([])));
$this->commandTester->execute([ $this->commandTester->execute([
@ -75,8 +75,8 @@ class GetShortUrlVisitsCommandTest extends TestCase
$shortCode = 'abc123'; $shortCode = 'abc123';
$startDate = 'foo'; $startDate = 'foo';
$this->visitsHelper->expects($this->once())->method('visitsForShortUrl')->with( $this->visitsHelper->expects($this->once())->method('visitsForShortUrl')->with(
$this->equalTo(ShortUrlIdentifier::fromShortCodeAndDomain($shortCode)), ShortUrlIdentifier::fromShortCodeAndDomain($shortCode),
$this->equalTo(new VisitsParams(DateRange::allTime())), new VisitsParams(DateRange::allTime()),
)->willReturn(new Paginator(new ArrayAdapter([]))); )->willReturn(new Paginator(new ArrayAdapter([])));
$this->commandTester->execute([ $this->commandTester->execute([
@ -99,7 +99,7 @@ class GetShortUrlVisitsCommandTest extends TestCase
); );
$shortCode = 'abc123'; $shortCode = 'abc123';
$this->visitsHelper->expects($this->once())->method('visitsForShortUrl')->with( $this->visitsHelper->expects($this->once())->method('visitsForShortUrl')->with(
$this->equalTo(ShortUrlIdentifier::fromShortCodeAndDomain($shortCode)), ShortUrlIdentifier::fromShortCodeAndDomain($shortCode),
$this->anything(), $this->anything(),
)->willReturn(new Paginator(new ArrayAdapter([$visit]))); )->willReturn(new Paginator(new ArrayAdapter([$visit])));

View file

@ -73,7 +73,7 @@ class ListShortUrlsCommandTest extends TestCase
} }
$this->shortUrlService->expects($this->once())->method('listShortUrls')->with( $this->shortUrlService->expects($this->once())->method('listShortUrls')->with(
$this->equalTo(ShortUrlsParams::emptyInstance()), ShortUrlsParams::emptyInstance(),
)->willReturn(new Paginator(new ArrayAdapter($data))); )->willReturn(new Paginator(new ArrayAdapter($data)));
$this->commandTester->setInputs(['n']); $this->commandTester->setInputs(['n']);
@ -94,7 +94,7 @@ class ListShortUrlsCommandTest extends TestCase
{ {
$page = 5; $page = 5;
$this->shortUrlService->expects($this->once())->method('listShortUrls')->with( $this->shortUrlService->expects($this->once())->method('listShortUrls')->with(
$this->equalTo(ShortUrlsParams::fromRawData(['page' => $page])), ShortUrlsParams::fromRawData(['page' => $page]),
)->willReturn(new Paginator(new ArrayAdapter([]))); )->willReturn(new Paginator(new ArrayAdapter([])));
$this->commandTester->setInputs(['y']); $this->commandTester->setInputs(['y']);
@ -112,7 +112,7 @@ class ListShortUrlsCommandTest extends TestCase
ApiKey $apiKey, ApiKey $apiKey,
): void { ): void {
$this->shortUrlService->expects($this->once())->method('listShortUrls')->with( $this->shortUrlService->expects($this->once())->method('listShortUrls')->with(
$this->equalTo(ShortUrlsParams::emptyInstance()), ShortUrlsParams::emptyInstance(),
)->willReturn(new Paginator(new ArrayAdapter([ )->willReturn(new Paginator(new ArrayAdapter([
ShortUrl::fromMeta(ShortUrlCreation::fromRawData([ ShortUrl::fromMeta(ShortUrlCreation::fromRawData([
'longUrl' => 'foo.com', 'longUrl' => 'foo.com',
@ -187,16 +187,14 @@ class ListShortUrlsCommandTest extends TestCase
?string $startDate = null, ?string $startDate = null,
?string $endDate = null, ?string $endDate = null,
): void { ): void {
$this->shortUrlService->expects($this->once())->method('listShortUrls')->with( $this->shortUrlService->expects($this->once())->method('listShortUrls')->with(ShortUrlsParams::fromRawData([
$this->equalTo(ShortUrlsParams::fromRawData([ 'page' => $page,
'page' => $page, 'searchTerm' => $searchTerm,
'searchTerm' => $searchTerm, 'tags' => $tags,
'tags' => $tags, 'tagsMode' => $tagsMode,
'tagsMode' => $tagsMode, 'startDate' => $startDate !== null ? Chronos::parse($startDate)->toAtomString() : null,
'startDate' => $startDate !== null ? Chronos::parse($startDate)->toAtomString() : null, 'endDate' => $endDate !== null ? Chronos::parse($endDate)->toAtomString() : null,
'endDate' => $endDate !== null ? Chronos::parse($endDate)->toAtomString() : null, ]))->willReturn(new Paginator(new ArrayAdapter([])));
])),
)->willReturn(new Paginator(new ArrayAdapter([])));
$this->commandTester->setInputs(['n']); $this->commandTester->setInputs(['n']);
$this->commandTester->execute($commandArgs); $this->commandTester->execute($commandArgs);
@ -249,11 +247,9 @@ class ListShortUrlsCommandTest extends TestCase
*/ */
public function orderByIsProperlyComputed(array $commandArgs, ?string $expectedOrderBy): void public function orderByIsProperlyComputed(array $commandArgs, ?string $expectedOrderBy): void
{ {
$this->shortUrlService->expects($this->once())->method('listShortUrls')->with( $this->shortUrlService->expects($this->once())->method('listShortUrls')->with(ShortUrlsParams::fromRawData([
$this->equalTo(ShortUrlsParams::fromRawData([ 'orderBy' => $expectedOrderBy,
'orderBy' => $expectedOrderBy, ]))->willReturn(new Paginator(new ArrayAdapter([])));
])),
)->willReturn(new Paginator(new ArrayAdapter([])));
$this->commandTester->setInputs(['n']); $this->commandTester->setInputs(['n']);
$this->commandTester->execute($commandArgs); $this->commandTester->execute($commandArgs);
@ -271,18 +267,16 @@ class ListShortUrlsCommandTest extends TestCase
/** @test */ /** @test */
public function requestingAllElementsWillSetItemsPerPage(): void public function requestingAllElementsWillSetItemsPerPage(): void
{ {
$this->shortUrlService->expects($this->once())->method('listShortUrls')->with( $this->shortUrlService->expects($this->once())->method('listShortUrls')->with(ShortUrlsParams::fromRawData([
$this->equalTo(ShortUrlsParams::fromRawData([ 'page' => 1,
'page' => 1, 'searchTerm' => null,
'searchTerm' => null, 'tags' => [],
'tags' => [], 'tagsMode' => TagsMode::ANY->value,
'tagsMode' => TagsMode::ANY->value, 'startDate' => null,
'startDate' => null, 'endDate' => null,
'endDate' => null, 'orderBy' => null,
'orderBy' => null, 'itemsPerPage' => Paginator::ALL_ITEMS,
'itemsPerPage' => Paginator::ALL_ITEMS, ]))->willReturn(new Paginator(new ArrayAdapter([])));
])),
)->willReturn(new Paginator(new ArrayAdapter([])));
$this->commandTester->execute(['--all' => true]); $this->commandTester->execute(['--all' => true]);
} }

View file

@ -38,7 +38,7 @@ class ResolveUrlCommandTest extends TestCase
$expectedUrl = 'http://domain.com/foo/bar'; $expectedUrl = 'http://domain.com/foo/bar';
$shortUrl = ShortUrl::withLongUrl($expectedUrl); $shortUrl = ShortUrl::withLongUrl($expectedUrl);
$this->urlResolver->expects($this->once())->method('resolveShortUrl')->with( $this->urlResolver->expects($this->once())->method('resolveShortUrl')->with(
$this->equalTo(ShortUrlIdentifier::fromShortCodeAndDomain($shortCode)), ShortUrlIdentifier::fromShortCodeAndDomain($shortCode),
)->willReturn($shortUrl); )->willReturn($shortUrl);
$this->commandTester->execute(['shortCode' => $shortCode]); $this->commandTester->execute(['shortCode' => $shortCode]);
@ -52,9 +52,9 @@ class ResolveUrlCommandTest extends TestCase
$identifier = ShortUrlIdentifier::fromShortCodeAndDomain('abc123'); $identifier = ShortUrlIdentifier::fromShortCodeAndDomain('abc123');
$shortCode = $identifier->shortCode; $shortCode = $identifier->shortCode;
$this->urlResolver->expects($this->once())->method('resolveShortUrl')->with( $this->urlResolver->expects($this->once())->method('resolveShortUrl')->with($identifier)->willThrowException(
$this->equalTo($identifier), ShortUrlNotFoundException::fromNotFound($identifier),
)->willThrowException(ShortUrlNotFoundException::fromNotFound($identifier)); );
$this->commandTester->execute(['shortCode' => $shortCode]); $this->commandTester->execute(['shortCode' => $shortCode]);
$output = $this->commandTester->getDisplay(); $output = $this->commandTester->getDisplay();

View file

@ -37,7 +37,7 @@ class DeleteTagsCommandTest extends TestCase
public function serviceIsInvokedOnSuccess(): void public function serviceIsInvokedOnSuccess(): void
{ {
$tagNames = ['foo', 'bar']; $tagNames = ['foo', 'bar'];
$this->tagService->expects($this->once())->method('deleteTags')->with($this->equalTo($tagNames)); $this->tagService->expects($this->once())->method('deleteTags')->with($tagNames);
$this->commandTester->execute([ $this->commandTester->execute([
'--name' => $tagNames, '--name' => $tagNames,

View file

@ -45,13 +45,10 @@ class GetTagVisitsCommandTest extends TestCase
VisitLocation::fromGeolocation(new Location('', 'Spain', '', 'Madrid', 0, 0, '')), VisitLocation::fromGeolocation(new Location('', 'Spain', '', 'Madrid', 0, 0, '')),
); );
$tag = 'abc123'; $tag = 'abc123';
$this->visitsHelper->expects($this->once())->method('visitsForTag')->with( $this->visitsHelper->expects($this->once())->method('visitsForTag')->with($tag, $this->anything())->willReturn(
$this->equalTo($tag), new Paginator(new ArrayAdapter([$visit])),
$this->anything(),
)->willReturn(new Paginator(new ArrayAdapter([$visit])));
$this->stringifier->expects($this->once())->method('stringify')->with($this->equalTo($shortUrl))->willReturn(
'the_short_url',
); );
$this->stringifier->expects($this->once())->method('stringify')->with($shortUrl)->willReturn('the_short_url');
$this->commandTester->execute(['tag' => $tag]); $this->commandTester->execute(['tag' => $tag]);
$output = $this->commandTester->getDisplay(); $output = $this->commandTester->getDisplay();

View file

@ -33,7 +33,7 @@ class RenameTagCommandTest extends TestCase
$oldName = 'foo'; $oldName = 'foo';
$newName = 'bar'; $newName = 'bar';
$this->tagService->expects($this->once())->method('renameTag')->with( $this->tagService->expects($this->once())->method('renameTag')->with(
$this->equalTo(TagRenaming::fromNames($oldName, $newName)), TagRenaming::fromNames($oldName, $newName),
)->willThrowException(TagNotFoundException::fromTag('foo')); )->willThrowException(TagNotFoundException::fromTag('foo'));
$this->commandTester->execute([ $this->commandTester->execute([
@ -51,7 +51,7 @@ class RenameTagCommandTest extends TestCase
$oldName = 'foo'; $oldName = 'foo';
$newName = 'bar'; $newName = 'bar';
$this->tagService->expects($this->once())->method('renameTag')->with( $this->tagService->expects($this->once())->method('renameTag')->with(
$this->equalTo(TagRenaming::fromNames($oldName, $newName)), TagRenaming::fromNames($oldName, $newName),
)->willReturn(new Tag($newName)); )->willReturn(new Tag($newName));
$this->commandTester->execute([ $this->commandTester->execute([

View file

@ -47,9 +47,7 @@ class GetNonOrphanVisitsCommandTest extends TestCase
$this->visitsHelper->expects($this->once())->method('nonOrphanVisits')->withAnyParameters()->willReturn( $this->visitsHelper->expects($this->once())->method('nonOrphanVisits')->withAnyParameters()->willReturn(
new Paginator(new ArrayAdapter([$visit])), new Paginator(new ArrayAdapter([$visit])),
); );
$this->stringifier->expects($this->once())->method('stringify')->with($this->equalTo($shortUrl))->willReturn( $this->stringifier->expects($this->once())->method('stringify')->with($shortUrl)->willReturn('the_short_url');
'the_short_url',
);
$this->commandTester->execute([]); $this->commandTester->execute([]);
$output = $this->commandTester->getDisplay(); $output = $this->commandTester->getDisplay();

View file

@ -26,7 +26,7 @@ class ProcessRunnerTest extends TestCase
$this->helper = $this->createMock(ProcessHelper::class); $this->helper = $this->createMock(ProcessHelper::class);
$this->formatter = $this->createMock(DebugFormatterHelper::class); $this->formatter = $this->createMock(DebugFormatterHelper::class);
$helperSet = $this->createMock(HelperSet::class); $helperSet = $this->createMock(HelperSet::class);
$helperSet->method('get')->with($this->equalTo('debug_formatter'))->willReturn($this->formatter); $helperSet->method('get')->with('debug_formatter')->willReturn($this->formatter);
$this->helper->method('getHelperSet')->with()->willReturn($helperSet); $this->helper->method('getHelperSet')->with()->willReturn($helperSet);
$this->process = $this->createMock(Process::class); $this->process = $this->createMock(Process::class);
$this->output = $this->createMock(OutputInterface::class); $this->output = $this->createMock(OutputInterface::class);

View file

@ -34,16 +34,10 @@ class ShlinkTableTest extends TestCase
$this->baseTable->expects($this->once())->method('setStyle')->with( $this->baseTable->expects($this->once())->method('setStyle')->with(
$this->isInstanceOf(TableStyle::class), $this->isInstanceOf(TableStyle::class),
)->willReturnSelf(); )->willReturnSelf();
$this->baseTable->expects($this->once())->method('setHeaders')->with( $this->baseTable->expects($this->once())->method('setHeaders')->with($headers)->willReturnSelf();
$this->equalTo($headers), $this->baseTable->expects($this->once())->method('setRows')->with($rows)->willReturnSelf();
)->willReturnSelf(); $this->baseTable->expects($this->once())->method('setFooterTitle')->with($footerTitle)->willReturnSelf();
$this->baseTable->expects($this->once())->method('setRows')->with($this->equalTo($rows))->willReturnSelf(); $this->baseTable->expects($this->once())->method('setHeaderTitle')->with($headerTitle)->willReturnSelf();
$this->baseTable->expects($this->once())->method('setFooterTitle')->with(
$this->equalTo($footerTitle),
)->willReturnSelf();
$this->baseTable->expects($this->once())->method('setHeaderTitle')->with(
$this->equalTo($headerTitle),
)->willReturnSelf();
$this->baseTable->expects($this->once())->method('render')->with()->willReturnSelf(); $this->baseTable->expects($this->once())->method('render')->with()->willReturnSelf();
$this->shlinkTable->render($headers, $rows, $footerTitle, $headerTitle); $this->shlinkTable->render($headers, $rows, $footerTitle, $headerTitle);

View file

@ -21,8 +21,9 @@ class PersistenceShortUrlRelationResolver implements ShortUrlRelationResolverInt
/** @var array<string, Tag> */ /** @var array<string, Tag> */
private array $memoizedNewTags = []; private array $memoizedNewTags = [];
public function __construct(private EntityManagerInterface $em) public function __construct(private readonly EntityManagerInterface $em)
{ {
// Registering this as an event listener will make the postFlush method to be called automatically
$this->em->getEventManager()->addEventListener(Events::postFlush, $this); $this->em->getEventManager()->addEventListener(Events::postFlush, $this);
} }
@ -61,7 +62,7 @@ class PersistenceShortUrlRelationResolver implements ShortUrlRelationResolverInt
return new Collections\ArrayCollection(map($tags, function (string $tagName) use ($repo): Tag { return new Collections\ArrayCollection(map($tags, function (string $tagName) use ($repo): Tag {
// Memoize only new tags, and let doctrine handle objects hydrated from persistence // Memoize only new tags, and let doctrine handle objects hydrated from persistence
$tag = $repo->findOneBy(['name' => $tagName]) ?? $this->memoizeNewTag($tagName); $tag = $repo->findOneBy(['name' => $tagName]) ?? $this->memoizeNewTag($tagName);
$this->em->persist($tag); $this->em->persist($tag);
return $tag; return $tag;

View file

@ -34,7 +34,7 @@ class PixelActionTest extends TestCase
{ {
$shortCode = 'abc123'; $shortCode = 'abc123';
$this->urlResolver->expects($this->once())->method('resolveEnabledShortUrl')->with( $this->urlResolver->expects($this->once())->method('resolveEnabledShortUrl')->with(
$this->equalTo(ShortUrlIdentifier::fromShortCodeAndDomain($shortCode, '')), ShortUrlIdentifier::fromShortCodeAndDomain($shortCode, ''),
)->willReturn(ShortUrl::withLongUrl('http://domain.com/foo/bar')); )->willReturn(ShortUrl::withLongUrl('http://domain.com/foo/bar'));
$this->requestTracker->expects($this->once())->method('trackIfApplicable')->withAnyParameters(); $this->requestTracker->expects($this->once())->method('trackIfApplicable')->withAnyParameters();

View file

@ -42,7 +42,7 @@ class QrCodeActionTest extends TestCase
{ {
$shortCode = 'abc123'; $shortCode = 'abc123';
$this->urlResolver->expects($this->once())->method('resolveEnabledShortUrl')->with( $this->urlResolver->expects($this->once())->method('resolveEnabledShortUrl')->with(
$this->equalTo(ShortUrlIdentifier::fromShortCodeAndDomain($shortCode, '')), ShortUrlIdentifier::fromShortCodeAndDomain($shortCode, ''),
)->willThrowException(ShortUrlNotFoundException::fromNotFound(ShortUrlIdentifier::fromShortCodeAndDomain(''))); )->willThrowException(ShortUrlNotFoundException::fromNotFound(ShortUrlIdentifier::fromShortCodeAndDomain('')));
$delegate = $this->createMock(RequestHandlerInterface::class); $delegate = $this->createMock(RequestHandlerInterface::class);
$delegate->expects($this->once())->method('handle')->withAnyParameters()->willReturn(new Response()); $delegate->expects($this->once())->method('handle')->withAnyParameters()->willReturn(new Response());
@ -55,7 +55,7 @@ class QrCodeActionTest extends TestCase
{ {
$shortCode = 'abc123'; $shortCode = 'abc123';
$this->urlResolver->expects($this->once())->method('resolveEnabledShortUrl')->with( $this->urlResolver->expects($this->once())->method('resolveEnabledShortUrl')->with(
$this->equalTo(ShortUrlIdentifier::fromShortCodeAndDomain($shortCode, '')), ShortUrlIdentifier::fromShortCodeAndDomain($shortCode, ''),
)->willReturn(ShortUrl::createEmpty()); )->willReturn(ShortUrl::createEmpty());
$delegate = $this->createMock(RequestHandlerInterface::class); $delegate = $this->createMock(RequestHandlerInterface::class);
$delegate->expects($this->never())->method('handle'); $delegate->expects($this->never())->method('handle');
@ -77,7 +77,7 @@ class QrCodeActionTest extends TestCase
): void { ): void {
$code = 'abc123'; $code = 'abc123';
$this->urlResolver->method('resolveEnabledShortUrl')->with( $this->urlResolver->method('resolveEnabledShortUrl')->with(
$this->equalTo(ShortUrlIdentifier::fromShortCodeAndDomain($code, '')), ShortUrlIdentifier::fromShortCodeAndDomain($code, ''),
)->willReturn(ShortUrl::createEmpty()); )->willReturn(ShortUrl::createEmpty());
$delegate = $this->createMock(RequestHandlerInterface::class); $delegate = $this->createMock(RequestHandlerInterface::class);
$req = (new ServerRequest())->withAttribute('shortCode', $code)->withQueryParams($query); $req = (new ServerRequest())->withAttribute('shortCode', $code)->withQueryParams($query);
@ -110,7 +110,7 @@ class QrCodeActionTest extends TestCase
): void { ): void {
$code = 'abc123'; $code = 'abc123';
$this->urlResolver->method('resolveEnabledShortUrl')->with( $this->urlResolver->method('resolveEnabledShortUrl')->with(
$this->equalTo(ShortUrlIdentifier::fromShortCodeAndDomain($code, '')), ShortUrlIdentifier::fromShortCodeAndDomain($code, ''),
)->willReturn(ShortUrl::createEmpty()); )->willReturn(ShortUrl::createEmpty());
$delegate = $this->createMock(RequestHandlerInterface::class); $delegate = $this->createMock(RequestHandlerInterface::class);
@ -201,7 +201,7 @@ class QrCodeActionTest extends TestCase
->withAttribute('shortCode', $code); ->withAttribute('shortCode', $code);
$this->urlResolver->method('resolveEnabledShortUrl')->with( $this->urlResolver->method('resolveEnabledShortUrl')->with(
$this->equalTo(ShortUrlIdentifier::fromShortCodeAndDomain($code, '')), ShortUrlIdentifier::fromShortCodeAndDomain($code, ''),
)->willReturn(ShortUrl::withLongUrl('https://shlink.io')); )->willReturn(ShortUrl::withLongUrl('https://shlink.io'));
$delegate = $this->createMock(RequestHandlerInterface::class); $delegate = $this->createMock(RequestHandlerInterface::class);

View file

@ -50,12 +50,12 @@ class RedirectActionTest extends TestCase
$shortCode = 'abc123'; $shortCode = 'abc123';
$shortUrl = ShortUrl::withLongUrl(self::LONG_URL); $shortUrl = ShortUrl::withLongUrl(self::LONG_URL);
$this->urlResolver->expects($this->once())->method('resolveEnabledShortUrl')->with( $this->urlResolver->expects($this->once())->method('resolveEnabledShortUrl')->with(
$this->equalTo(ShortUrlIdentifier::fromShortCodeAndDomain($shortCode, '')), ShortUrlIdentifier::fromShortCodeAndDomain($shortCode, ''),
)->willReturn($shortUrl); )->willReturn($shortUrl);
$this->requestTracker->expects($this->once())->method('trackIfApplicable'); $this->requestTracker->expects($this->once())->method('trackIfApplicable');
$expectedResp = new Response\RedirectResponse(self::LONG_URL); $expectedResp = new Response\RedirectResponse(self::LONG_URL);
$this->redirectRespHelper->expects($this->once())->method('buildRedirectResponse')->with( $this->redirectRespHelper->expects($this->once())->method('buildRedirectResponse')->with(
$this->equalTo(self::LONG_URL), self::LONG_URL,
)->willReturn($expectedResp); )->willReturn($expectedResp);
$request = (new ServerRequest())->withAttribute('shortCode', $shortCode); $request = (new ServerRequest())->withAttribute('shortCode', $shortCode);
@ -69,7 +69,7 @@ class RedirectActionTest extends TestCase
{ {
$shortCode = 'abc123'; $shortCode = 'abc123';
$this->urlResolver->expects($this->once())->method('resolveEnabledShortUrl')->with( $this->urlResolver->expects($this->once())->method('resolveEnabledShortUrl')->with(
$this->equalTo(ShortUrlIdentifier::fromShortCodeAndDomain($shortCode, '')), ShortUrlIdentifier::fromShortCodeAndDomain($shortCode, ''),
)->willThrowException(ShortUrlNotFoundException::fromNotFound(ShortUrlIdentifier::fromShortCodeAndDomain(''))); )->willThrowException(ShortUrlNotFoundException::fromNotFound(ShortUrlIdentifier::fromShortCodeAndDomain('')));
$this->requestTracker->expects($this->never())->method('trackIfApplicable'); $this->requestTracker->expects($this->never())->method('trackIfApplicable');

View file

@ -43,9 +43,9 @@ class NotFoundRedirectResolverTest extends TestCase
string $expectedRedirectTo, string $expectedRedirectTo,
): void { ): void {
$expectedResp = new Response(); $expectedResp = new Response();
$this->helper->expects($this->once())->method('buildRedirectResponse')->with( $this->helper->expects($this->once())->method('buildRedirectResponse')->with($expectedRedirectTo)->willReturn(
$this->equalTo($expectedRedirectTo), $expectedResp,
)->willReturn($expectedResp); );
$resp = $this->resolver->resolveRedirectResponse($notFoundType, $redirectConfig, $uri); $resp = $this->resolver->resolveRedirectResponse($notFoundType, $redirectConfig, $uri);

View file

@ -27,9 +27,7 @@ class CrawlingHelperTest extends TestCase
{ {
$repo = $this->createMock(ShortUrlRepositoryInterface::class); $repo = $this->createMock(ShortUrlRepositoryInterface::class);
$repo->expects($this->once())->method('findCrawlableShortCodes')->willReturn([]); $repo->expects($this->once())->method('findCrawlableShortCodes')->willReturn([]);
$this->em->expects($this->once())->method('getRepository')->with($this->equalTo(ShortUrl::class))->willReturn( $this->em->expects($this->once())->method('getRepository')->with(ShortUrl::class)->willReturn($repo);
$repo,
);
$result = $this->helper->listCrawlableShortCodes(); $result = $this->helper->listCrawlableShortCodes();
foreach ($result as $shortCode) { foreach ($result as $shortCode) {

View file

@ -36,10 +36,8 @@ class DomainServiceTest extends TestCase
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);
$repo->expects($this->once())->method('findDomains')->with($this->equalTo($apiKey))->willReturn($domains); $repo->expects($this->once())->method('findDomains')->with($apiKey)->willReturn($domains);
$this->em->expects($this->once())->method('getRepository')->with($this->equalTo(Domain::class))->willReturn( $this->em->expects($this->once())->method('getRepository')->with(Domain::class)->willReturn($repo);
$repo,
);
$result = $this->domainService->listDomains($apiKey); $result = $this->domainService->listDomains($apiKey);
@ -105,10 +103,7 @@ class DomainServiceTest extends TestCase
/** @test */ /** @test */
public function getDomainThrowsExceptionWhenDomainIsNotFound(): void public function getDomainThrowsExceptionWhenDomainIsNotFound(): void
{ {
$this->em->expects($this->once())->method('find')->with( $this->em->expects($this->once())->method('find')->with(Domain::class, '123')->willReturn(null);
$this->equalTo(Domain::class),
$this->equalTo('123'),
)->willReturn(null);
$this->expectException(DomainNotFoundException::class); $this->expectException(DomainNotFoundException::class);
@ -119,10 +114,7 @@ class DomainServiceTest extends TestCase
public function getDomainReturnsEntityWhenFound(): void public function getDomainReturnsEntityWhenFound(): void
{ {
$domain = Domain::withAuthority(''); $domain = Domain::withAuthority('');
$this->em->expects($this->once())->method('find')->with( $this->em->expects($this->once())->method('find')->with(Domain::class, '123')->willReturn($domain);
$this->equalTo(Domain::class),
$this->equalTo('123'),
)->willReturn($domain);
$result = $this->domainService->getDomain('123'); $result = $this->domainService->getDomain('123');
@ -137,15 +129,11 @@ class DomainServiceTest extends TestCase
{ {
$authority = 'example.com'; $authority = 'example.com';
$repo = $this->createMock(DomainRepositoryInterface::class); $repo = $this->createMock(DomainRepositoryInterface::class);
$repo->method('findOneByAuthority')->with($this->equalTo($authority), $this->equalTo($apiKey))->willReturn( $repo->method('findOneByAuthority')->with($authority, $apiKey)->willReturn(
$foundDomain, $foundDomain,
); );
$this->em->expects($this->once())->method('getRepository')->with($this->equalTo(Domain::class))->willReturn( $this->em->expects($this->once())->method('getRepository')->with(Domain::class)->willReturn($repo);
$repo, $this->em->expects($this->once())->method('persist')->with($foundDomain ?? $this->isInstanceOf(Domain::class));
);
$this->em->expects($this->once())->method('persist')->with(
$foundDomain !== null ? $this->equalTo($foundDomain) : $this->isInstanceOf(Domain::class),
);
$this->em->expects($this->once())->method('flush'); $this->em->expects($this->once())->method('flush');
$result = $this->domainService->getOrCreate($authority, $apiKey); $result = $this->domainService->getOrCreate($authority, $apiKey);
@ -162,12 +150,8 @@ class DomainServiceTest extends TestCase
$domain = Domain::withAuthority($authority)->setId('1'); $domain = Domain::withAuthority($authority)->setId('1');
$apiKey = ApiKey::fromMeta(ApiKeyMeta::withRoles(RoleDefinition::forDomain($domain))); $apiKey = ApiKey::fromMeta(ApiKeyMeta::withRoles(RoleDefinition::forDomain($domain)));
$repo = $this->createMock(DomainRepositoryInterface::class); $repo = $this->createMock(DomainRepositoryInterface::class);
$repo->method('findOneByAuthority')->with($this->equalTo($authority), $this->equalTo($apiKey))->willReturn( $repo->method('findOneByAuthority')->with($authority, $apiKey)->willReturn(null);
null, $this->em->expects($this->once())->method('getRepository')->with(Domain::class)->willReturn($repo);
);
$this->em->expects($this->once())->method('getRepository')->with($this->equalTo(Domain::class))->willReturn(
$repo,
);
$this->em->expects($this->never())->method('persist'); $this->em->expects($this->never())->method('persist');
$this->em->expects($this->never())->method('flush'); $this->em->expects($this->never())->method('flush');
@ -184,15 +168,9 @@ class DomainServiceTest extends TestCase
{ {
$authority = 'example.com'; $authority = 'example.com';
$repo = $this->createMock(DomainRepositoryInterface::class); $repo = $this->createMock(DomainRepositoryInterface::class);
$repo->method('findOneByAuthority')->with($this->equalTo($authority), $this->equalTo($apiKey))->willReturn( $repo->method('findOneByAuthority')->with($authority, $apiKey)->willReturn($foundDomain);
$foundDomain, $this->em->expects($this->once())->method('getRepository')->with(Domain::class)->willReturn($repo);
); $this->em->expects($this->once())->method('persist')->with($foundDomain ?? $this->isInstanceOf(Domain::class));
$this->em->expects($this->once())->method('getRepository')->with($this->equalTo(Domain::class))->willReturn(
$repo,
);
$this->em->expects($this->once())->method('persist')->with(
$foundDomain !== null ? $this->equalTo($foundDomain) : $this->isInstanceOf(Domain::class),
);
$this->em->expects($this->once())->method('flush'); $this->em->expects($this->once())->method('flush');
$result = $this->domainService->configureNotFoundRedirects($authority, NotFoundRedirects::withRedirects( $result = $this->domainService->configureNotFoundRedirects($authority, NotFoundRedirects::withRedirects(

View file

@ -51,9 +51,7 @@ class NotFoundRedirectHandlerTest extends TestCase
$expectedResp = new Response(); $expectedResp = new Response();
$setUp($this->domainService, $this->resolver); $setUp($this->domainService, $this->resolver);
$this->next->expects($this->once())->method('handle')->with($this->equalTo($this->req))->willReturn( $this->next->expects($this->once())->method('handle')->with($this->req)->willReturn($expectedResp);
$expectedResp,
);
$result = $this->middleware->process($this->req, $this->next); $result = $this->middleware->process($this->req, $this->next);
@ -105,7 +103,7 @@ class NotFoundRedirectHandlerTest extends TestCase
$this->domainService->expects($this->once())->method('findByAuthority')->withAnyParameters()->willReturn(null); $this->domainService->expects($this->once())->method('findByAuthority')->withAnyParameters()->willReturn(null);
$this->resolver->expects($this->once())->method('resolveRedirectResponse')->with( $this->resolver->expects($this->once())->method('resolveRedirectResponse')->with(
$this->isInstanceOf(NotFoundType::class), $this->isInstanceOf(NotFoundType::class),
$this->equalTo($this->redirectOptions), $this->redirectOptions,
$this->isInstanceOf(UriInterface::class), $this->isInstanceOf(UriInterface::class),
)->willReturn($expectedResp); )->willReturn($expectedResp);
$this->next->expects($this->never())->method('handle'); $this->next->expects($this->never())->method('handle');
@ -126,7 +124,7 @@ class NotFoundRedirectHandlerTest extends TestCase
); );
$this->resolver->expects($this->once())->method('resolveRedirectResponse')->with( $this->resolver->expects($this->once())->method('resolveRedirectResponse')->with(
$this->isInstanceOf(NotFoundType::class), $this->isInstanceOf(NotFoundType::class),
$this->equalTo($domain), $domain,
$this->isInstanceOf(UriInterface::class), $this->isInstanceOf(UriInterface::class),
)->willReturn($expectedResp); )->willReturn($expectedResp);
$this->next->expects($this->never())->method('handle'); $this->next->expects($this->never())->method('handle');

View file

@ -35,10 +35,8 @@ class NotFoundTrackerMiddlewareTest extends TestCase
/** @test */ /** @test */
public function delegatesIntoRequestTracker(): void public function delegatesIntoRequestTracker(): void
{ {
$this->handler->expects($this->once())->method('handle')->with($this->equalTo($this->request)); $this->handler->expects($this->once())->method('handle')->with($this->request);
$this->requestTracker->expects($this->once())->method('trackNotFoundIfApplicable')->with( $this->requestTracker->expects($this->once())->method('trackNotFoundIfApplicable')->with($this->request);
$this->equalTo($this->request),
);
$this->middleware->process($this->request, $this->handler); $this->middleware->process($this->request, $this->handler);
} }

View file

@ -32,7 +32,7 @@ class CloseDbConnectionEventListenerDelegatorTest extends TestCase
}; };
}; };
$this->container->expects($this->once())->method('get')->with($this->equalTo('em'))->willReturn( $this->container->expects($this->once())->method('get')->with('em')->willReturn(
$this->createMock(ReopeningEntityManagerInterface::class), $this->createMock(ReopeningEntityManagerInterface::class),
); );

View file

@ -31,7 +31,7 @@ class LocateUnlocatedVisitsTest extends TestCase
/** @test */ /** @test */
public function locatorIsCalledWhenInvoked(): void public function locatorIsCalledWhenInvoked(): void
{ {
$this->locator->expects($this->once())->method('locateUnlocatedVisits')->with($this->equalTo($this->listener)); $this->locator->expects($this->once())->method('locateUnlocatedVisits')->with($this->listener);
($this->listener)(new GeoLiteDbCreated()); ($this->listener)(new GeoLiteDbCreated());
} }
@ -41,9 +41,9 @@ class LocateUnlocatedVisitsTest extends TestCase
$visit = Visit::forBasePath(Visitor::emptyInstance()); $visit = Visit::forBasePath(Visitor::emptyInstance());
$location = Location::emptyInstance(); $location = Location::emptyInstance();
$this->visitToLocation->expects($this->once())->method('resolveVisitLocation')->with( $this->visitToLocation->expects($this->once())->method('resolveVisitLocation')->with($visit)->willReturn(
$this->equalTo($visit), $location,
)->willReturn($location); );
$result = $this->listener->geolocateVisit($visit); $result = $this->listener->geolocateVisit($visit);

View file

@ -53,18 +53,13 @@ class LocateVisitTest extends TestCase
public function invalidVisitLogsWarning(): void public function invalidVisitLogsWarning(): void
{ {
$event = new UrlVisited('123'); $event = new UrlVisited('123');
$this->em->expects($this->once())->method('find')->with( $this->em->expects($this->once())->method('find')->with(Visit::class, '123')->willReturn(null);
$this->equalTo(Visit::class),
$this->equalTo('123'),
)->willReturn(null);
$this->em->expects($this->never())->method('flush'); $this->em->expects($this->never())->method('flush');
$this->logger->expects($this->once())->method('warning')->with( $this->logger->expects($this->once())->method('warning')->with(
$this->equalTo('Tried to locate visit with id "{visitId}", but it does not exist.'), 'Tried to locate visit with id "{visitId}", but it does not exist.',
$this->equalTo(['visitId' => 123]), ['visitId' => 123],
);
$this->eventDispatcher->expects($this->never())->method('dispatch')->with(
$this->equalTo(new VisitLocated('123')),
); );
$this->eventDispatcher->expects($this->never())->method('dispatch')->with(new VisitLocated('123'));
$this->ipLocationResolver->expects($this->never())->method('resolveIpLocation'); $this->ipLocationResolver->expects($this->never())->method('resolveIpLocation');
($this->locateVisit)($event); ($this->locateVisit)($event);
@ -74,19 +69,16 @@ class LocateVisitTest extends TestCase
public function nonExistingGeoLiteDbLogsWarning(): void public function nonExistingGeoLiteDbLogsWarning(): void
{ {
$event = new UrlVisited('123'); $event = new UrlVisited('123');
$this->em->expects($this->once())->method('find')->with( $this->em->expects($this->once())->method('find')->with(Visit::class, '123')->willReturn(
$this->equalTo(Visit::class), Visit::forValidShortUrl(ShortUrl::createEmpty(), new Visitor('', '', '1.2.3.4', '')),
$this->equalTo('123'), );
)->willReturn(Visit::forValidShortUrl(ShortUrl::createEmpty(), new Visitor('', '', '1.2.3.4', '')));
$this->em->expects($this->never())->method('flush'); $this->em->expects($this->never())->method('flush');
$this->dbUpdater->expects($this->once())->method('databaseFileExists')->withAnyParameters()->willReturn(false); $this->dbUpdater->expects($this->once())->method('databaseFileExists')->withAnyParameters()->willReturn(false);
$this->logger->expects($this->once())->method('warning')->with( $this->logger->expects($this->once())->method('warning')->with(
$this->equalTo('Tried to locate visit with id "{visitId}", but a GeoLite2 db was not found.'), 'Tried to locate visit with id "{visitId}", but a GeoLite2 db was not found.',
$this->equalTo(['visitId' => 123]), ['visitId' => 123],
);
$this->eventDispatcher->expects($this->once())->method('dispatch')->with(
$this->equalTo(new VisitLocated('123')),
); );
$this->eventDispatcher->expects($this->once())->method('dispatch')->with(new VisitLocated('123'));
$this->ipLocationResolver->expects($this->never())->method('resolveIpLocation'); $this->ipLocationResolver->expects($this->never())->method('resolveIpLocation');
($this->locateVisit)($event); ($this->locateVisit)($event);
@ -96,22 +88,19 @@ class LocateVisitTest extends TestCase
public function invalidAddressLogsWarning(): void public function invalidAddressLogsWarning(): void
{ {
$event = new UrlVisited('123'); $event = new UrlVisited('123');
$this->em->expects($this->once())->method('find')->with( $this->em->expects($this->once())->method('find')->with(Visit::class, '123')->willReturn(
$this->equalTo(Visit::class), Visit::forValidShortUrl(ShortUrl::createEmpty(), new Visitor('', '', '1.2.3.4', '')),
$this->equalTo('123'), );
)->willReturn(Visit::forValidShortUrl(ShortUrl::createEmpty(), new Visitor('', '', '1.2.3.4', '')));
$this->em->expects($this->never())->method('flush'); $this->em->expects($this->never())->method('flush');
$this->dbUpdater->expects($this->once())->method('databaseFileExists')->withAnyParameters()->willReturn(true); $this->dbUpdater->expects($this->once())->method('databaseFileExists')->withAnyParameters()->willReturn(true);
$this->ipLocationResolver->expects( $this->ipLocationResolver->expects(
$this->once(), $this->once(),
)->method('resolveIpLocation')->withAnyParameters()->willThrowException(WrongIpException::fromIpAddress('')); )->method('resolveIpLocation')->withAnyParameters()->willThrowException(WrongIpException::fromIpAddress(''));
$this->logger->expects($this->once())->method('warning')->with( $this->logger->expects($this->once())->method('warning')->with(
$this->equalTo('Tried to locate visit with id "{visitId}", but its address seems to be wrong. {e}'), 'Tried to locate visit with id "{visitId}", but its address seems to be wrong. {e}',
$this->isType('array'), $this->isType('array'),
); );
$this->eventDispatcher->expects($this->once())->method('dispatch')->with( $this->eventDispatcher->expects($this->once())->method('dispatch')->with(new VisitLocated('123'));
$this->equalTo(new VisitLocated('123')),
);
($this->locateVisit)($event); ($this->locateVisit)($event);
} }
@ -120,22 +109,19 @@ class LocateVisitTest extends TestCase
public function unhandledExceptionLogsError(): void public function unhandledExceptionLogsError(): void
{ {
$event = new UrlVisited('123'); $event = new UrlVisited('123');
$this->em->expects($this->once())->method('find')->with( $this->em->expects($this->once())->method('find')->with(Visit::class, '123')->willReturn(
$this->equalTo(Visit::class), Visit::forValidShortUrl(ShortUrl::createEmpty(), new Visitor('', '', '1.2.3.4', '')),
$this->equalTo('123'), );
)->willReturn(Visit::forValidShortUrl(ShortUrl::createEmpty(), new Visitor('', '', '1.2.3.4', '')));
$this->em->expects($this->never())->method('flush'); $this->em->expects($this->never())->method('flush');
$this->dbUpdater->expects($this->once())->method('databaseFileExists')->withAnyParameters()->willReturn(true); $this->dbUpdater->expects($this->once())->method('databaseFileExists')->withAnyParameters()->willReturn(true);
$this->ipLocationResolver->expects( $this->ipLocationResolver->expects(
$this->once(), $this->once(),
)->method('resolveIpLocation')->withAnyParameters()->willThrowException(new OutOfRangeException()); )->method('resolveIpLocation')->withAnyParameters()->willThrowException(new OutOfRangeException());
$this->logger->expects($this->once())->method('error')->with( $this->logger->expects($this->once())->method('error')->with(
$this->equalTo('An unexpected error occurred while trying to locate visit with id "{visitId}". {e}'), 'An unexpected error occurred while trying to locate visit with id "{visitId}". {e}',
$this->isType('array'), $this->isType('array'),
); );
$this->eventDispatcher->expects($this->once())->method('dispatch')->with( $this->eventDispatcher->expects($this->once())->method('dispatch')->with(new VisitLocated('123'));
$this->equalTo(new VisitLocated('123')),
);
($this->locateVisit)($event); ($this->locateVisit)($event);
} }
@ -147,17 +133,12 @@ class LocateVisitTest extends TestCase
public function nonLocatableVisitsResolveToEmptyLocations(Visit $visit): void public function nonLocatableVisitsResolveToEmptyLocations(Visit $visit): void
{ {
$event = new UrlVisited('123'); $event = new UrlVisited('123');
$this->em->expects($this->once())->method('find')->with( $this->em->expects($this->once())->method('find')->with(Visit::class, '123')->willReturn($visit);
$this->equalTo(Visit::class),
$this->equalTo('123'),
)->willReturn($visit);
$this->em->expects($this->once())->method('flush'); $this->em->expects($this->once())->method('flush');
$this->dbUpdater->expects($this->once())->method('databaseFileExists')->withAnyParameters()->willReturn(true); $this->dbUpdater->expects($this->once())->method('databaseFileExists')->withAnyParameters()->willReturn(true);
$this->ipLocationResolver->expects($this->never())->method('resolveIpLocation'); $this->ipLocationResolver->expects($this->never())->method('resolveIpLocation');
$this->eventDispatcher->expects($this->once())->method('dispatch')->with( $this->eventDispatcher->expects($this->once())->method('dispatch')->with(new VisitLocated('123'));
$this->equalTo(new VisitLocated('123')),
);
$this->logger->expects($this->never())->method('warning'); $this->logger->expects($this->never())->method('warning');
($this->locateVisit)($event); ($this->locateVisit)($event);
@ -184,19 +165,14 @@ class LocateVisitTest extends TestCase
$location = new Location('', '', '', '', 0.0, 0.0, ''); $location = new Location('', '', '', '', 0.0, 0.0, '');
$event = UrlVisited::withOriginalIpAddress('123', $originalIpAddress); $event = UrlVisited::withOriginalIpAddress('123', $originalIpAddress);
$this->em->expects($this->once())->method('find')->with( $this->em->expects($this->once())->method('find')->with(Visit::class, '123')->willReturn($visit);
$this->equalTo(Visit::class),
$this->equalTo('123'),
)->willReturn($visit);
$this->em->expects($this->once())->method('flush'); $this->em->expects($this->once())->method('flush');
$this->dbUpdater->expects($this->once())->method('databaseFileExists')->withAnyParameters()->willReturn(true); $this->dbUpdater->expects($this->once())->method('databaseFileExists')->withAnyParameters()->willReturn(true);
$this->ipLocationResolver->expects($this->once())->method('resolveIpLocation')->with( $this->ipLocationResolver->expects($this->once())->method('resolveIpLocation')->with($ipAddr)->willReturn(
$this->equalTo($ipAddr), $location,
)->willReturn($location);
$this->eventDispatcher->expects($this->once())->method('dispatch')->with(
$this->equalTo(new VisitLocated('123')),
); );
$this->eventDispatcher->expects($this->once())->method('dispatch')->with(new VisitLocated('123'));
$this->logger->expects($this->never())->method('warning'); $this->logger->expects($this->never())->method('warning');
($this->locateVisit)($event); ($this->locateVisit)($event);

View file

@ -42,15 +42,12 @@ class NotifyNewShortUrlToMercureTest extends TestCase
/** @test */ /** @test */
public function messageIsLoggedWhenShortUrlIsNotFound(): void public function messageIsLoggedWhenShortUrlIsNotFound(): void
{ {
$this->em->expects($this->once())->method('find')->with( $this->em->expects($this->once())->method('find')->with(ShortUrl::class, '123')->willReturn(null);
$this->equalTo(ShortUrl::class),
$this->equalTo('123'),
)->willReturn(null);
$this->helper->expects($this->never())->method('publishUpdate'); $this->helper->expects($this->never())->method('publishUpdate');
$this->updatesGenerator->expects($this->never())->method('newShortUrlUpdate'); $this->updatesGenerator->expects($this->never())->method('newShortUrlUpdate');
$this->logger->expects($this->once())->method('warning')->with( $this->logger->expects($this->once())->method('warning')->with(
$this->equalTo('Tried to notify {name} for new short URL with id "{shortUrlId}", but it does not exist.'), 'Tried to notify {name} for new short URL with id "{shortUrlId}", but it does not exist.',
$this->equalTo(['shortUrlId' => '123', 'name' => 'Mercure']), ['shortUrlId' => '123', 'name' => 'Mercure'],
); );
$this->logger->expects($this->never())->method('debug'); $this->logger->expects($this->never())->method('debug');
@ -63,14 +60,11 @@ class NotifyNewShortUrlToMercureTest extends TestCase
$shortUrl = ShortUrl::withLongUrl(''); $shortUrl = ShortUrl::withLongUrl('');
$update = Update::forTopicAndPayload('', []); $update = Update::forTopicAndPayload('', []);
$this->em->expects($this->once())->method('find')->with( $this->em->expects($this->once())->method('find')->with(ShortUrl::class, '123')->willReturn($shortUrl);
$this->equalTo(ShortUrl::class), $this->updatesGenerator->expects($this->once())->method('newShortUrlUpdate')->with($shortUrl)->willReturn(
$this->equalTo('123'), $update,
)->willReturn($shortUrl); );
$this->updatesGenerator->expects($this->once())->method('newShortUrlUpdate')->with( $this->helper->expects($this->once())->method('publishUpdate')->with($update);
$this->equalTo($shortUrl),
)->willReturn($update);
$this->helper->expects($this->once())->method('publishUpdate')->with($this->equalTo($update));
$this->logger->expects($this->never())->method('warning'); $this->logger->expects($this->never())->method('warning');
$this->logger->expects($this->never())->method('debug'); $this->logger->expects($this->never())->method('debug');
@ -85,19 +79,17 @@ class NotifyNewShortUrlToMercureTest extends TestCase
$e = new Exception('Error'); $e = new Exception('Error');
$this->em->expects($this->once())->method('find')->with( $this->em->expects($this->once())->method('find')->with(
$this->equalTo(ShortUrl::class), ShortUrl::class,
$this->equalTo('123'), '123',
)->willReturn($shortUrl); )->willReturn($shortUrl);
$this->updatesGenerator->expects($this->once())->method('newShortUrlUpdate')->with( $this->updatesGenerator->expects($this->once())->method('newShortUrlUpdate')->with($shortUrl)->willReturn(
$this->equalTo($shortUrl), $update,
)->willReturn($update); );
$this->helper->expects($this->once())->method('publishUpdate')->with( $this->helper->expects($this->once())->method('publishUpdate')->with($update)->willThrowException($e);
$this->equalTo($update),
)->willThrowException($e);
$this->logger->expects($this->never())->method('warning'); $this->logger->expects($this->never())->method('warning');
$this->logger->expects($this->once())->method('debug')->with( $this->logger->expects($this->once())->method('debug')->with(
$this->equalTo('Error while trying to notify {name} with new short URL. {e}'), 'Error while trying to notify {name} with new short URL. {e}',
$this->equalTo(['e' => $e, 'name' => 'Mercure']), ['e' => $e, 'name' => 'Mercure'],
); );
($this->listener)(new ShortUrlCreated('123')); ($this->listener)(new ShortUrlCreated('123'));

View file

@ -41,13 +41,10 @@ class NotifyVisitToMercureTest extends TestCase
public function notificationsAreNotSentWhenVisitCannotBeFound(): void public function notificationsAreNotSentWhenVisitCannotBeFound(): void
{ {
$visitId = '123'; $visitId = '123';
$this->em->expects($this->once())->method('find')->with( $this->em->expects($this->once())->method('find')->with(Visit::class, $visitId)->willReturn(null);
$this->equalTo(Visit::class),
$this->equalTo($visitId),
)->willReturn(null);
$this->logger->expects($this->once())->method('warning')->with( $this->logger->expects($this->once())->method('warning')->with(
$this->equalTo('Tried to notify {name} for visit with id "{visitId}", but it does not exist.'), 'Tried to notify {name} for visit with id "{visitId}", but it does not exist.',
$this->equalTo(['visitId' => $visitId, 'name' => 'Mercure']), ['visitId' => $visitId, 'name' => 'Mercure'],
); );
$this->logger->expects($this->never())->method('debug'); $this->logger->expects($this->never())->method('debug');
$this->updatesGenerator->expects($this->never())->method('newShortUrlVisitUpdate'); $this->updatesGenerator->expects($this->never())->method('newShortUrlVisitUpdate');
@ -65,20 +62,15 @@ class NotifyVisitToMercureTest extends TestCase
$visit = Visit::forValidShortUrl(ShortUrl::createEmpty(), Visitor::emptyInstance()); $visit = Visit::forValidShortUrl(ShortUrl::createEmpty(), Visitor::emptyInstance());
$update = Update::forTopicAndPayload('', []); $update = Update::forTopicAndPayload('', []);
$this->em->expects($this->once())->method('find')->with( $this->em->expects($this->once())->method('find')->with(Visit::class, $visitId)->willReturn($visit);
$this->equalTo(Visit::class),
$this->equalTo($visitId),
)->willReturn($visit);
$this->logger->expects($this->never())->method('warning'); $this->logger->expects($this->never())->method('warning');
$this->logger->expects($this->never())->method('debug'); $this->logger->expects($this->never())->method('debug');
$this->updatesGenerator->expects($this->once())->method('newShortUrlVisitUpdate')->with( $this->updatesGenerator->expects($this->once())->method('newShortUrlVisitUpdate')->with($visit)->willReturn(
$this->equalTo($visit), $update,
)->willReturn($update); );
$this->updatesGenerator->expects($this->never())->method('newOrphanVisitUpdate'); $this->updatesGenerator->expects($this->never())->method('newOrphanVisitUpdate');
$this->updatesGenerator->expects($this->once())->method('newVisitUpdate')->with( $this->updatesGenerator->expects($this->once())->method('newVisitUpdate')->with($visit)->willReturn($update);
$this->equalTo($visit), $this->helper->expects($this->exactly(2))->method('publishUpdate')->with($update);
)->willReturn($update);
$this->helper->expects($this->exactly(2))->method('publishUpdate')->with($this->equalTo($update));
($this->listener)(new VisitLocated($visitId)); ($this->listener)(new VisitLocated($visitId));
} }
@ -91,25 +83,18 @@ class NotifyVisitToMercureTest extends TestCase
$update = Update::forTopicAndPayload('', []); $update = Update::forTopicAndPayload('', []);
$e = new RuntimeException('Error'); $e = new RuntimeException('Error');
$this->em->expects($this->once())->method('find')->with( $this->em->expects($this->once())->method('find')->with(Visit::class, $visitId)->willReturn($visit);
$this->equalTo(Visit::class),
$this->equalTo($visitId),
)->willReturn($visit);
$this->logger->expects($this->never())->method('warning'); $this->logger->expects($this->never())->method('warning');
$this->logger->expects($this->once())->method('debug')->with( $this->logger->expects($this->once())->method('debug')->with(
$this->equalTo('Error while trying to notify {name} with new visit. {e}'), 'Error while trying to notify {name} with new visit. {e}',
$this->equalTo(['e' => $e, 'name' => 'Mercure']), ['e' => $e, 'name' => 'Mercure'],
);
$this->updatesGenerator->expects($this->once())->method('newShortUrlVisitUpdate')->with($visit)->willReturn(
$update,
); );
$this->updatesGenerator->expects($this->once())->method('newShortUrlVisitUpdate')->with(
$this->equalTo($visit),
)->willReturn($update);
$this->updatesGenerator->expects($this->never())->method('newOrphanVisitUpdate'); $this->updatesGenerator->expects($this->never())->method('newOrphanVisitUpdate');
$this->updatesGenerator->expects($this->once())->method('newVisitUpdate')->with( $this->updatesGenerator->expects($this->once())->method('newVisitUpdate')->with($visit)->willReturn($update);
$this->equalTo($visit), $this->helper->expects($this->once())->method('publishUpdate')->with($update)->willThrowException($e);
)->willReturn($update);
$this->helper->expects($this->once())->method('publishUpdate')->with(
$this->equalTo($update),
)->willThrowException($e);
($this->listener)(new VisitLocated($visitId)); ($this->listener)(new VisitLocated($visitId));
} }
@ -123,18 +108,15 @@ class NotifyVisitToMercureTest extends TestCase
$visitId = '123'; $visitId = '123';
$update = Update::forTopicAndPayload('', []); $update = Update::forTopicAndPayload('', []);
$this->em->expects($this->once())->method('find')->with( $this->em->expects($this->once())->method('find')->with(Visit::class, $visitId)->willReturn($visit);
$this->equalTo(Visit::class),
$this->equalTo($visitId),
)->willReturn($visit);
$this->logger->expects($this->never())->method('warning'); $this->logger->expects($this->never())->method('warning');
$this->logger->expects($this->never())->method('debug'); $this->logger->expects($this->never())->method('debug');
$this->updatesGenerator->expects($this->never())->method('newShortUrlVisitUpdate'); $this->updatesGenerator->expects($this->never())->method('newShortUrlVisitUpdate');
$this->updatesGenerator->expects($this->once())->method('newOrphanVisitUpdate')->with( $this->updatesGenerator->expects($this->once())->method('newOrphanVisitUpdate')->with($visit)->willReturn(
$this->equalTo($visit), $update,
)->willReturn($update); );
$this->updatesGenerator->expects($this->never())->method('newVisitUpdate'); $this->updatesGenerator->expects($this->never())->method('newVisitUpdate');
$this->helper->expects($this->once())->method('publishUpdate')->with($this->equalTo($update)); $this->helper->expects($this->once())->method('publishUpdate')->with($update);
($this->listener)(new VisitLocated($visitId)); ($this->listener)(new VisitLocated($visitId));
} }

View file

@ -52,14 +52,11 @@ class NotifyVisitToWebHooksTest extends TestCase
/** @test */ /** @test */
public function invalidVisitDoesNotPerformAnyRequest(): void public function invalidVisitDoesNotPerformAnyRequest(): void
{ {
$this->em->expects($this->once())->method('find')->with( $this->em->expects($this->once())->method('find')->with(Visit::class, '1')->willReturn(null);
$this->equalTo(Visit::class),
$this->equalTo('1'),
)->willReturn(null);
$this->httpClient->expects($this->never())->method('requestAsync'); $this->httpClient->expects($this->never())->method('requestAsync');
$this->logger->expects($this->once())->method('warning')->with( $this->logger->expects($this->once())->method('warning')->with(
$this->equalTo('Tried to notify webhooks for visit with id "{visitId}", but it does not exist.'), 'Tried to notify webhooks for visit with id "{visitId}", but it does not exist.',
$this->equalTo(['visitId' => '1']), ['visitId' => '1'],
); );
$this->createListener(['foo', 'bar'])(new VisitLocated('1')); $this->createListener(['foo', 'bar'])(new VisitLocated('1'));
@ -68,10 +65,9 @@ class NotifyVisitToWebHooksTest extends TestCase
/** @test */ /** @test */
public function orphanVisitDoesNotPerformAnyRequestWhenDisabled(): void public function orphanVisitDoesNotPerformAnyRequestWhenDisabled(): void
{ {
$this->em->expects($this->once())->method('find')->with( $this->em->expects($this->once())->method('find')->with(Visit::class, '1')->willReturn(
$this->equalTo(Visit::class), Visit::forBasePath(Visitor::emptyInstance()),
$this->equalTo('1'), );
)->willReturn(Visit::forBasePath(Visitor::emptyInstance()));
$this->httpClient->expects($this->never())->method('requestAsync'); $this->httpClient->expects($this->never())->method('requestAsync');
$this->logger->expects($this->never())->method('warning'); $this->logger->expects($this->never())->method('warning');
@ -87,12 +83,9 @@ class NotifyVisitToWebHooksTest extends TestCase
$webhooks = ['foo', 'invalid', 'bar', 'baz']; $webhooks = ['foo', 'invalid', 'bar', 'baz'];
$invalidWebhooks = ['invalid', 'baz']; $invalidWebhooks = ['invalid', 'baz'];
$this->em->expects($this->once())->method('find')->with( $this->em->expects($this->once())->method('find')->with(Visit::class, '1')->willReturn($visit);
$this->equalTo(Visit::class),
$this->equalTo('1'),
)->willReturn($visit);
$this->httpClient->expects($this->exactly(count($webhooks)))->method('requestAsync')->with( $this->httpClient->expects($this->exactly(count($webhooks)))->method('requestAsync')->with(
$this->equalTo(RequestMethodInterface::METHOD_POST), RequestMethodInterface::METHOD_POST,
$this->istype('string'), $this->istype('string'),
$this->callback(function (array $requestOptions) use ($expectedResponseKeys) { $this->callback(function (array $requestOptions) use ($expectedResponseKeys) {
Assert::assertArrayHasKey(RequestOptions::HEADERS, $requestOptions); Assert::assertArrayHasKey(RequestOptions::HEADERS, $requestOptions);
@ -114,7 +107,7 @@ class NotifyVisitToWebHooksTest extends TestCase
return $shouldReject ? new RejectedPromise(new Exception('')) : new FulfilledPromise(''); return $shouldReject ? new RejectedPromise(new Exception('')) : new FulfilledPromise('');
}); });
$this->logger->expects($this->exactly(count($invalidWebhooks)))->method('warning')->with( $this->logger->expects($this->exactly(count($invalidWebhooks)))->method('warning')->with(
$this->equalTo('Failed to notify visit with id "{visitId}" to webhook "{webhook}". {e}'), 'Failed to notify visit with id "{visitId}" to webhook "{webhook}". {e}',
$this->callback(function (array $extra): bool { $this->callback(function (array $extra): bool {
Assert::assertArrayHasKey('webhook', $extra); Assert::assertArrayHasKey('webhook', $extra);
Assert::assertArrayHasKey('visitId', $extra); Assert::assertArrayHasKey('visitId', $extra);

View file

@ -51,13 +51,10 @@ class NotifyNewShortUrlToRabbitMqTest extends TestCase
public function notificationsAreNotSentWhenShortUrlCannotBeFound(): void public function notificationsAreNotSentWhenShortUrlCannotBeFound(): void
{ {
$shortUrlId = '123'; $shortUrlId = '123';
$this->em->expects($this->once())->method('find')->with( $this->em->expects($this->once())->method('find')->with(ShortUrl::class, $shortUrlId)->willReturn(null);
$this->equalTo(ShortUrl::class),
$this->equalTo($shortUrlId),
)->willReturn(null);
$this->logger->expects($this->once())->method('warning')->with( $this->logger->expects($this->once())->method('warning')->with(
$this->equalTo('Tried to notify {name} for new short URL with id "{shortUrlId}", but it does not exist.'), 'Tried to notify {name} for new short URL with id "{shortUrlId}", but it does not exist.',
$this->equalTo(['shortUrlId' => $shortUrlId, 'name' => 'RabbitMQ']), ['shortUrlId' => $shortUrlId, 'name' => 'RabbitMQ'],
); );
$this->logger->expects($this->never())->method('debug'); $this->logger->expects($this->never())->method('debug');
$this->helper->expects($this->never())->method('publishUpdate'); $this->helper->expects($this->never())->method('publishUpdate');
@ -70,14 +67,13 @@ class NotifyNewShortUrlToRabbitMqTest extends TestCase
{ {
$shortUrlId = '123'; $shortUrlId = '123';
$update = Update::forTopicAndPayload(Topic::NEW_SHORT_URL->value, []); $update = Update::forTopicAndPayload(Topic::NEW_SHORT_URL->value, []);
$this->em->expects($this->once())->method('find')->with( $this->em->expects($this->once())->method('find')->with(ShortUrl::class, $shortUrlId)->willReturn(
$this->equalTo(ShortUrl::class), ShortUrl::withLongUrl(''),
$this->equalTo($shortUrlId), );
)->willReturn(ShortUrl::withLongUrl(''));
$this->updatesGenerator->expects($this->once())->method('newShortUrlUpdate')->with( $this->updatesGenerator->expects($this->once())->method('newShortUrlUpdate')->with(
$this->isInstanceOf(ShortUrl::class), $this->isInstanceOf(ShortUrl::class),
)->willReturn($update); )->willReturn($update);
$this->helper->expects($this->once())->method('publishUpdate')->with($this->equalTo($update)); $this->helper->expects($this->once())->method('publishUpdate')->with($update);
$this->logger->expects($this->never())->method('debug'); $this->logger->expects($this->never())->method('debug');
($this->listener())(new ShortUrlCreated($shortUrlId)); ($this->listener())(new ShortUrlCreated($shortUrlId));
@ -91,19 +87,16 @@ class NotifyNewShortUrlToRabbitMqTest extends TestCase
{ {
$shortUrlId = '123'; $shortUrlId = '123';
$update = Update::forTopicAndPayload(Topic::NEW_SHORT_URL->value, []); $update = Update::forTopicAndPayload(Topic::NEW_SHORT_URL->value, []);
$this->em->expects($this->once())->method('find')->with( $this->em->expects($this->once())->method('find')->with(ShortUrl::class, $shortUrlId)->willReturn(
$this->equalTo(ShortUrl::class), ShortUrl::withLongUrl(''),
$this->equalTo($shortUrlId), );
)->willReturn(ShortUrl::withLongUrl(''));
$this->updatesGenerator->expects($this->once())->method('newShortUrlUpdate')->with( $this->updatesGenerator->expects($this->once())->method('newShortUrlUpdate')->with(
$this->isInstanceOf(ShortUrl::class), $this->isInstanceOf(ShortUrl::class),
)->willReturn($update); )->willReturn($update);
$this->helper->expects($this->once())->method('publishUpdate')->with( $this->helper->expects($this->once())->method('publishUpdate')->with($update)->willThrowException($e);
$this->equalTo($update),
)->willThrowException($e);
$this->logger->expects($this->once())->method('debug')->with( $this->logger->expects($this->once())->method('debug')->with(
$this->equalTo('Error while trying to notify {name} with new short URL. {e}'), 'Error while trying to notify {name} with new short URL. {e}',
$this->equalTo(['e' => $e, 'name' => 'RabbitMQ']), ['e' => $e, 'name' => 'RabbitMQ'],
); );
($this->listener())(new ShortUrlCreated($shortUrlId)); ($this->listener())(new ShortUrlCreated($shortUrlId));

View file

@ -59,13 +59,10 @@ class NotifyVisitToRabbitMqTest extends TestCase
public function notificationsAreNotSentWhenVisitCannotBeFound(): void public function notificationsAreNotSentWhenVisitCannotBeFound(): void
{ {
$visitId = '123'; $visitId = '123';
$this->em->expects($this->once())->method('find')->with( $this->em->expects($this->once())->method('find')->with(Visit::class, $visitId)->willReturn(null);
$this->equalTo(Visit::class),
$this->equalTo($visitId),
)->willReturn(null);
$this->logger->expects($this->once())->method('warning')->with( $this->logger->expects($this->once())->method('warning')->with(
$this->equalTo('Tried to notify {name} for visit with id "{visitId}", but it does not exist.'), 'Tried to notify {name} for visit with id "{visitId}", but it does not exist.',
$this->equalTo(['visitId' => $visitId, 'name' => 'RabbitMQ']), ['visitId' => $visitId, 'name' => 'RabbitMQ'],
); );
$this->logger->expects($this->never())->method('debug'); $this->logger->expects($this->never())->method('debug');
$this->helper->expects($this->never())->method('publishUpdate'); $this->helper->expects($this->never())->method('publishUpdate');
@ -80,10 +77,7 @@ class NotifyVisitToRabbitMqTest extends TestCase
public function expectedChannelsAreNotifiedBasedOnTheVisitType(Visit $visit, array $expectedChannels): void public function expectedChannelsAreNotifiedBasedOnTheVisitType(Visit $visit, array $expectedChannels): void
{ {
$visitId = '123'; $visitId = '123';
$this->em->expects($this->once())->method('find')->with( $this->em->expects($this->once())->method('find')->with(Visit::class, $visitId)->willReturn($visit);
$this->equalTo(Visit::class),
$this->equalTo($visitId),
)->willReturn($visit);
each($expectedChannels, function (string $method): void { each($expectedChannels, function (string $method): void {
$this->updatesGenerator->expects($this->once())->method($method)->with( $this->updatesGenerator->expects($this->once())->method($method)->with(
$this->isInstanceOf(Visit::class), $this->isInstanceOf(Visit::class),
@ -121,17 +115,16 @@ class NotifyVisitToRabbitMqTest extends TestCase
public function printsDebugMessageInCaseOfError(Throwable $e): void public function printsDebugMessageInCaseOfError(Throwable $e): void
{ {
$visitId = '123'; $visitId = '123';
$this->em->expects($this->once())->method('find')->with( $this->em->expects($this->once())->method('find')->with(Visit::class, $visitId)->willReturn(
$this->equalTo(Visit::class), Visit::forBasePath(Visitor::emptyInstance()),
$this->equalTo($visitId), );
)->willReturn(Visit::forBasePath(Visitor::emptyInstance()));
$this->updatesGenerator->expects($this->once())->method('newOrphanVisitUpdate')->with( $this->updatesGenerator->expects($this->once())->method('newOrphanVisitUpdate')->with(
$this->isInstanceOf(Visit::class), $this->isInstanceOf(Visit::class),
)->willReturn(Update::forTopicAndPayload('', [])); )->willReturn(Update::forTopicAndPayload('', []));
$this->helper->expects($this->once())->method('publishUpdate')->withAnyParameters()->willThrowException($e); $this->helper->expects($this->once())->method('publishUpdate')->withAnyParameters()->willThrowException($e);
$this->logger->expects($this->once())->method('debug')->with( $this->logger->expects($this->once())->method('debug')->with(
$this->equalTo('Error while trying to notify {name} with new visit. {e}'), 'Error while trying to notify {name} with new visit. {e}',
$this->equalTo(['e' => $e, 'name' => 'RabbitMQ']), ['e' => $e, 'name' => 'RabbitMQ'],
); );
($this->listener())(new VisitLocated($visitId)); ($this->listener())(new VisitLocated($visitId));
@ -155,10 +148,7 @@ class NotifyVisitToRabbitMqTest extends TestCase
callable $expect, callable $expect,
): void { ): void {
$visitId = '123'; $visitId = '123';
$this->em->expects($this->once())->method('find')->with( $this->em->expects($this->once())->method('find')->with(Visit::class, $visitId)->willReturn($visit);
$this->equalTo(Visit::class),
$this->equalTo($visitId),
)->willReturn($visit);
$setup($this->updatesGenerator); $setup($this->updatesGenerator);
$expect($this->helper, $this->updatesGenerator); $expect($this->helper, $this->updatesGenerator);

View file

@ -54,19 +54,16 @@ class NotifyNewShortUrlToRedisTest extends TestCase
{ {
$shortUrlId = '123'; $shortUrlId = '123';
$update = Update::forTopicAndPayload(Topic::NEW_SHORT_URL->value, []); $update = Update::forTopicAndPayload(Topic::NEW_SHORT_URL->value, []);
$this->em->expects($this->once())->method('find')->with( $this->em->expects($this->once())->method('find')->with(ShortUrl::class, $shortUrlId)->willReturn(
$this->equalTo(ShortUrl::class), ShortUrl::withLongUrl(''),
$this->equalTo($shortUrlId), );
)->willReturn(ShortUrl::withLongUrl(''));
$this->updatesGenerator->expects($this->once())->method('newShortUrlUpdate')->with( $this->updatesGenerator->expects($this->once())->method('newShortUrlUpdate')->with(
$this->isInstanceOf(ShortUrl::class), $this->isInstanceOf(ShortUrl::class),
)->willReturn($update); )->willReturn($update);
$this->helper->expects($this->once())->method('publishUpdate')->with( $this->helper->expects($this->once())->method('publishUpdate')->with($update)->willThrowException($e);
$this->equalTo($update),
)->willThrowException($e);
$this->logger->expects($this->once())->method('debug')->with( $this->logger->expects($this->once())->method('debug')->with(
$this->equalTo('Error while trying to notify {name} with new short URL. {e}'), 'Error while trying to notify {name} with new short URL. {e}',
$this->equalTo(['e' => $e, 'name' => 'Redis pub/sub']), ['e' => $e, 'name' => 'Redis pub/sub'],
); );
$this->createListener()(new ShortUrlCreated($shortUrlId)); $this->createListener()(new ShortUrlCreated($shortUrlId));

View file

@ -53,17 +53,16 @@ class NotifyVisitToRedisTest extends TestCase
public function printsDebugMessageInCaseOfError(Throwable $e): void public function printsDebugMessageInCaseOfError(Throwable $e): void
{ {
$visitId = '123'; $visitId = '123';
$this->em->expects($this->once())->method('find')->with( $this->em->expects($this->once())->method('find')->with(Visit::class, $visitId)->willReturn(
$this->equalTo(Visit::class), Visit::forBasePath(Visitor::emptyInstance()),
$this->equalTo($visitId), );
)->willReturn(Visit::forBasePath(Visitor::emptyInstance()));
$this->updatesGenerator->expects($this->once())->method('newOrphanVisitUpdate')->with( $this->updatesGenerator->expects($this->once())->method('newOrphanVisitUpdate')->with(
$this->isInstanceOf(Visit::class), $this->isInstanceOf(Visit::class),
)->willReturn(Update::forTopicAndPayload('', [])); )->willReturn(Update::forTopicAndPayload('', []));
$this->helper->expects($this->once())->method('publishUpdate')->withAnyParameters()->willThrowException($e); $this->helper->expects($this->once())->method('publishUpdate')->withAnyParameters()->willThrowException($e);
$this->logger->expects($this->once())->method('debug')->with( $this->logger->expects($this->once())->method('debug')->with(
$this->equalTo('Error while trying to notify {name} with new visit. {e}'), 'Error while trying to notify {name} with new visit. {e}',
$this->equalTo(['e' => $e, 'name' => 'Redis pub/sub']), ['e' => $e, 'name' => 'Redis pub/sub'],
); );
$this->createListener()(new VisitLocated($visitId)); $this->createListener()(new VisitLocated($visitId));

View file

@ -39,8 +39,8 @@ class UpdateGeoLiteDbTest extends TestCase
$this->dbUpdater->expects($this->once())->method('checkDbUpdate')->withAnyParameters()->willThrowException($e); $this->dbUpdater->expects($this->once())->method('checkDbUpdate')->withAnyParameters()->willThrowException($e);
$this->logger->expects($this->once())->method('error')->with( $this->logger->expects($this->once())->method('error')->with(
$this->equalTo('GeoLite2 database download failed. {e}'), 'GeoLite2 database download failed. {e}',
$this->equalTo(['e' => $e]), ['e' => $e],
); );
$this->logger->expects($this->never())->method('notice'); $this->logger->expects($this->never())->method('notice');
$this->eventDispatcher->expects($this->never())->method('dispatch'); $this->eventDispatcher->expects($this->never())->method('dispatch');
@ -60,7 +60,7 @@ class UpdateGeoLiteDbTest extends TestCase
return GeolocationResult::DB_IS_UP_TO_DATE; return GeolocationResult::DB_IS_UP_TO_DATE;
}, },
); );
$this->logger->expects($this->once())->method('notice')->with($this->equalTo($expectedMessage)); $this->logger->expects($this->once())->method('notice')->with($expectedMessage);
$this->logger->expects($this->never())->method('error'); $this->logger->expects($this->never())->method('error');
$this->eventDispatcher->expects($this->never())->method('dispatch'); $this->eventDispatcher->expects($this->never())->method('dispatch');
@ -94,7 +94,7 @@ class UpdateGeoLiteDbTest extends TestCase
}, },
); );
$logNoticeExpectation = $expectedMessage !== null ? $this->once() : $this->never(); $logNoticeExpectation = $expectedMessage !== null ? $this->once() : $this->never();
$this->logger->expects($logNoticeExpectation)->method('notice')->with($this->equalTo($expectedMessage)); $this->logger->expects($logNoticeExpectation)->method('notice')->with($expectedMessage);
$this->logger->expects($this->never())->method('error'); $this->logger->expects($this->never())->method('error');
$this->eventDispatcher->expects($this->never())->method('dispatch'); $this->eventDispatcher->expects($this->never())->method('dispatch');
@ -123,7 +123,7 @@ class UpdateGeoLiteDbTest extends TestCase
): void { ): void {
$this->dbUpdater->expects($this->once())->method('checkDbUpdate')->withAnyParameters()->willReturn($result); $this->dbUpdater->expects($this->once())->method('checkDbUpdate')->withAnyParameters()->willReturn($result);
$this->eventDispatcher->expects($this->exactly($expectedDispatches))->method('dispatch')->with( $this->eventDispatcher->expects($this->exactly($expectedDispatches))->method('dispatch')->with(
$this->equalTo(new GeoLiteDbCreated()), new GeoLiteDbCreated(),
); );
($this->listener)(); ($this->listener)();

View file

@ -41,7 +41,7 @@ class ImportedLinksProcessorTest extends TestCase
{ {
$this->em = $this->createMock(EntityManagerInterface::class); $this->em = $this->createMock(EntityManagerInterface::class);
$this->repo = $this->createMock(ShortUrlRepositoryInterface::class); $this->repo = $this->createMock(ShortUrlRepositoryInterface::class);
$this->em->method('getRepository')->with($this->equalTo(ShortUrl::class))->willReturn($this->repo); $this->em->method('getRepository')->with(ShortUrl::class)->willReturn($this->repo);
$this->shortCodeHelper = $this->createMock(ShortCodeUniquenessHelperInterface::class); $this->shortCodeHelper = $this->createMock(ShortCodeUniquenessHelperInterface::class);
$batchHelper = $this->createMock(DoctrineBatchHelperInterface::class); $batchHelper = $this->createMock(DoctrineBatchHelperInterface::class);

View file

@ -6,10 +6,8 @@ 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\MockObject\MockObject;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Prophecy\Argument;
use Prophecy\PhpUnit\ProphecyTrait;
use Prophecy\Prophecy\ObjectProphecy;
use Shlinkio\Shlink\Core\Exception\DeleteShortUrlException; use Shlinkio\Shlink\Core\Exception\DeleteShortUrlException;
use Shlinkio\Shlink\Core\Options\DeleteShortUrlsOptions; use Shlinkio\Shlink\Core\Options\DeleteShortUrlsOptions;
use Shlinkio\Shlink\Core\ShortUrl\DeleteShortUrlService; use Shlinkio\Shlink\Core\ShortUrl\DeleteShortUrlService;
@ -25,10 +23,8 @@ use function sprintf;
class DeleteShortUrlServiceTest extends TestCase class DeleteShortUrlServiceTest extends TestCase
{ {
use ProphecyTrait; private MockObject $em;
private MockObject $urlResolver;
private ObjectProphecy $em;
private ObjectProphecy $urlResolver;
private string $shortCode; private string $shortCode;
protected function setUp(): void protected function setUp(): void
@ -38,10 +34,10 @@ class DeleteShortUrlServiceTest extends TestCase
)); ));
$this->shortCode = $shortUrl->getShortCode(); $this->shortCode = $shortUrl->getShortCode();
$this->em = $this->prophesize(EntityManagerInterface::class); $this->em = $this->createMock(EntityManagerInterface::class);
$this->urlResolver = $this->prophesize(ShortUrlResolverInterface::class); $this->urlResolver = $this->createMock(ShortUrlResolverInterface::class);
$this->urlResolver->resolveShortUrl(Argument::cetera())->willReturn($shortUrl); $this->urlResolver->method('resolveShortUrl')->willReturn($shortUrl);
} }
/** @test */ /** @test */
@ -63,13 +59,12 @@ class DeleteShortUrlServiceTest extends TestCase
{ {
$service = $this->createService(); $service = $this->createService();
$remove = $this->em->remove(Argument::type(ShortUrl::class))->willReturn(null); $this->em->expects($this->once())->method('remove')->with($this->isInstanceOf(ShortUrl::class))->willReturn(
$flush = $this->em->flush()->willReturn(null); null,
);
$this->em->expects($this->once())->method('flush')->with()->willReturn(null);
$service->deleteByShortCode(ShortUrlIdentifier::fromShortCodeAndDomain($this->shortCode), true); $service->deleteByShortCode(ShortUrlIdentifier::fromShortCodeAndDomain($this->shortCode), true);
$remove->shouldHaveBeenCalledOnce();
$flush->shouldHaveBeenCalledOnce();
} }
/** @test */ /** @test */
@ -77,13 +72,12 @@ class DeleteShortUrlServiceTest extends TestCase
{ {
$service = $this->createService(false); $service = $this->createService(false);
$remove = $this->em->remove(Argument::type(ShortUrl::class))->willReturn(null); $this->em->expects($this->once())->method('remove')->with($this->isInstanceOf(ShortUrl::class))->willReturn(
$flush = $this->em->flush()->willReturn(null); null,
);
$this->em->expects($this->once())->method('flush')->with()->willReturn(null);
$service->deleteByShortCode(ShortUrlIdentifier::fromShortCodeAndDomain($this->shortCode)); $service->deleteByShortCode(ShortUrlIdentifier::fromShortCodeAndDomain($this->shortCode));
$remove->shouldHaveBeenCalledOnce();
$flush->shouldHaveBeenCalledOnce();
} }
/** @test */ /** @test */
@ -91,20 +85,19 @@ class DeleteShortUrlServiceTest extends TestCase
{ {
$service = $this->createService(true, 100); $service = $this->createService(true, 100);
$remove = $this->em->remove(Argument::type(ShortUrl::class))->willReturn(null); $this->em->expects($this->once())->method('remove')->with($this->isInstanceOf(ShortUrl::class))->willReturn(
$flush = $this->em->flush()->willReturn(null); null,
);
$this->em->expects($this->once())->method('flush')->with()->willReturn(null);
$service->deleteByShortCode(ShortUrlIdentifier::fromShortCodeAndDomain($this->shortCode)); $service->deleteByShortCode(ShortUrlIdentifier::fromShortCodeAndDomain($this->shortCode));
$remove->shouldHaveBeenCalledOnce();
$flush->shouldHaveBeenCalledOnce();
} }
private function createService(bool $checkVisitsThreshold = true, int $visitsThreshold = 5): DeleteShortUrlService private function createService(bool $checkVisitsThreshold = true, int $visitsThreshold = 5): DeleteShortUrlService
{ {
return new DeleteShortUrlService($this->em->reveal(), new DeleteShortUrlsOptions( return new DeleteShortUrlService($this->em, new DeleteShortUrlsOptions(
$visitsThreshold, $visitsThreshold,
$checkVisitsThreshold, $checkVisitsThreshold,
), $this->urlResolver->reveal()); ), $this->urlResolver);
} }
} }

View file

@ -5,9 +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\MockObject\MockObject;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Prophecy\PhpUnit\ProphecyTrait;
use Prophecy\Prophecy\ObjectProphecy;
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\Helper\ShortCodeUniquenessHelper; use Shlinkio\Shlink\Core\ShortUrl\Helper\ShortCodeUniquenessHelper;
@ -16,19 +15,17 @@ use Shlinkio\Shlink\Core\ShortUrl\Repository\ShortUrlRepository;
class ShortCodeUniquenessHelperTest extends TestCase class ShortCodeUniquenessHelperTest extends TestCase
{ {
use ProphecyTrait;
private ShortCodeUniquenessHelper $helper; private ShortCodeUniquenessHelper $helper;
private ObjectProphecy $em; private MockObject $em;
private ObjectProphecy $shortUrl; private MockObject $shortUrl;
protected function setUp(): void protected function setUp(): void
{ {
$this->em = $this->prophesize(EntityManagerInterface::class); $this->em = $this->createMock(EntityManagerInterface::class);
$this->helper = new ShortCodeUniquenessHelper($this->em->reveal()); $this->helper = new ShortCodeUniquenessHelper($this->em);
$this->shortUrl = $this->prophesize(ShortUrl::class); $this->shortUrl = $this->createMock(ShortUrl::class);
$this->shortUrl->getShortCode()->willReturn('abc123'); $this->shortUrl->method('getShortCode')->willReturn('abc123');
} }
/** /**
@ -39,22 +36,22 @@ class ShortCodeUniquenessHelperTest extends TestCase
{ {
$callIndex = 0; $callIndex = 0;
$expectedCalls = 3; $expectedCalls = 3;
$repo = $this->prophesize(ShortUrlRepository::class); $repo = $this->createMock(ShortUrlRepository::class);
$shortCodeIsInUse = $repo->shortCodeIsInUseWithLock( $repo->expects($this->exactly($expectedCalls))->method('shortCodeIsInUseWithLock')->with(
ShortUrlIdentifier::fromShortCodeAndDomain('abc123', $expectedAuthority), ShortUrlIdentifier::fromShortCodeAndDomain('abc123', $expectedAuthority),
)->will(function () use (&$callIndex, $expectedCalls) { )->willReturnCallback(function () use (&$callIndex, $expectedCalls) {
$callIndex++; $callIndex++;
return $callIndex < $expectedCalls; return $callIndex < $expectedCalls;
}); });
$getRepo = $this->em->getRepository(ShortUrl::class)->willReturn($repo->reveal()); $this->em->expects($this->exactly($expectedCalls))->method('getRepository')->with(ShortUrl::class)->willReturn(
$this->shortUrl->getDomain()->willReturn($domain); $repo,
);
$this->shortUrl->method('getDomain')->willReturn($domain);
$this->shortUrl->expects($this->exactly($expectedCalls - 1))->method('regenerateShortCode')->with();
$result = $this->helper->ensureShortCodeUniqueness($this->shortUrl->reveal(), false); $result = $this->helper->ensureShortCodeUniqueness($this->shortUrl, false);
self::assertTrue($result); self::assertTrue($result);
$this->shortUrl->regenerateShortCode()->shouldHaveBeenCalledTimes($expectedCalls - 1);
$getRepo->shouldBeCalledTimes($expectedCalls);
$shortCodeIsInUse->shouldBeCalledTimes($expectedCalls);
} }
public function provideDomains(): iterable public function provideDomains(): iterable
@ -66,18 +63,16 @@ class ShortCodeUniquenessHelperTest extends TestCase
/** @test */ /** @test */
public function inUseSlugReturnsError(): void public function inUseSlugReturnsError(): void
{ {
$repo = $this->prophesize(ShortUrlRepository::class); $repo = $this->createMock(ShortUrlRepository::class);
$shortCodeIsInUse = $repo->shortCodeIsInUseWithLock( $repo->expects($this->once())->method('shortCodeIsInUseWithLock')->with(
ShortUrlIdentifier::fromShortCodeAndDomain('abc123'), ShortUrlIdentifier::fromShortCodeAndDomain('abc123'),
)->willReturn(true); )->willReturn(true);
$getRepo = $this->em->getRepository(ShortUrl::class)->willReturn($repo->reveal()); $this->em->expects($this->once())->method('getRepository')->with(ShortUrl::class)->willReturn($repo);
$this->shortUrl->getDomain()->willReturn(null); $this->shortUrl->method('getDomain')->willReturn(null);
$this->shortUrl->expects($this->never())->method('regenerateShortCode');
$result = $this->helper->ensureShortCodeUniqueness($this->shortUrl->reveal(), true); $result = $this->helper->ensureShortCodeUniqueness($this->shortUrl, true);
self::assertFalse($result); self::assertFalse($result);
$this->shortUrl->regenerateShortCode()->shouldNotHaveBeenCalled();
$getRepo->shouldBeCalledOnce();
$shortCodeIsInUse->shouldBeCalledOnce();
} }
} }

View file

@ -4,24 +4,21 @@ declare(strict_types=1);
namespace ShlinkioTest\Shlink\Core\ShortUrl\Helper; namespace ShlinkioTest\Shlink\Core\ShortUrl\Helper;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Prophecy\PhpUnit\ProphecyTrait;
use Prophecy\Prophecy\ObjectProphecy;
use Shlinkio\Shlink\Core\ShortUrl\Helper\ShortUrlTitleResolutionHelper; use Shlinkio\Shlink\Core\ShortUrl\Helper\ShortUrlTitleResolutionHelper;
use Shlinkio\Shlink\Core\ShortUrl\Model\ShortUrlCreation; use Shlinkio\Shlink\Core\ShortUrl\Model\ShortUrlCreation;
use Shlinkio\Shlink\Core\Util\UrlValidatorInterface; use Shlinkio\Shlink\Core\Util\UrlValidatorInterface;
class ShortUrlTitleResolutionHelperTest extends TestCase class ShortUrlTitleResolutionHelperTest extends TestCase
{ {
use ProphecyTrait;
private ShortUrlTitleResolutionHelper $helper; private ShortUrlTitleResolutionHelper $helper;
private ObjectProphecy $urlValidator; private MockObject $urlValidator;
protected function setUp(): void protected function setUp(): void
{ {
$this->urlValidator = $this->prophesize(UrlValidatorInterface::class); $this->urlValidator = $this->createMock(UrlValidatorInterface::class);
$this->helper = new ShortUrlTitleResolutionHelper($this->urlValidator->reveal()); $this->helper = new ShortUrlTitleResolutionHelper($this->urlValidator);
} }
/** /**
@ -31,14 +28,18 @@ class ShortUrlTitleResolutionHelperTest extends TestCase
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';
$this->urlValidator->expects($this->exactly($validateWithTitleCallsNum))->method('validateUrlWithTitle')->with(
$longUrl,
$this->isFalse(),
);
$this->urlValidator->expects($this->exactly($validateCallsNum))->method('validateUrl')->with(
$longUrl,
$this->isFalse(),
);
$this->helper->processTitleAndValidateUrl( $this->helper->processTitleAndValidateUrl(
ShortUrlCreation::fromRawData(['longUrl' => $longUrl, 'title' => $title]), ShortUrlCreation::fromRawData(['longUrl' => $longUrl, 'title' => $title]),
); );
$this->urlValidator->validateUrlWithTitle($longUrl, false)->shouldHaveBeenCalledTimes(
$validateWithTitleCallsNum,
);
$this->urlValidator->validateUrl($longUrl, false)->shouldHaveBeenCalledTimes($validateCallsNum);
} }
public function provideTitles(): iterable public function provideTitles(): iterable

View file

@ -9,10 +9,8 @@ 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\MockObject\MockObject;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Prophecy\Argument;
use Prophecy\PhpUnit\ProphecyTrait;
use Prophecy\Prophecy\ObjectProphecy;
use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface; use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface; use Psr\Http\Server\RequestHandlerInterface;
@ -32,22 +30,20 @@ use function str_starts_with;
class ExtraPathRedirectMiddlewareTest extends TestCase class ExtraPathRedirectMiddlewareTest extends TestCase
{ {
use ProphecyTrait; private MockObject $resolver;
private MockObject $requestTracker;
private ObjectProphecy $resolver; private MockObject $redirectionBuilder;
private ObjectProphecy $requestTracker; private MockObject $redirectResponseHelper;
private ObjectProphecy $redirectionBuilder; private MockObject $handler;
private ObjectProphecy $redirectResponseHelper;
private ObjectProphecy $handler;
protected function setUp(): void protected function setUp(): void
{ {
$this->resolver = $this->prophesize(ShortUrlResolverInterface::class); $this->resolver = $this->createMock(ShortUrlResolverInterface::class);
$this->requestTracker = $this->prophesize(RequestTrackerInterface::class); $this->requestTracker = $this->createMock(RequestTrackerInterface::class);
$this->redirectionBuilder = $this->prophesize(ShortUrlRedirectionBuilderInterface::class); $this->redirectionBuilder = $this->createMock(ShortUrlRedirectionBuilderInterface::class);
$this->redirectResponseHelper = $this->prophesize(RedirectResponseHelperInterface::class); $this->redirectResponseHelper = $this->createMock(RedirectResponseHelperInterface::class);
$this->handler = $this->prophesize(RequestHandlerInterface::class); $this->handler = $this->createMock(RequestHandlerInterface::class);
$this->handler->handle(Argument::cetera())->willReturn(new RedirectResponse('')); $this->handler->method('handle')->willReturn(new RedirectResponse(''));
} }
/** /**
@ -63,14 +59,13 @@ class ExtraPathRedirectMiddlewareTest extends TestCase
appendExtraPath: $appendExtraPath, appendExtraPath: $appendExtraPath,
multiSegmentSlugsEnabled: $multiSegmentEnabled, multiSegmentSlugsEnabled: $multiSegmentEnabled,
); );
$this->resolver->expects($this->never())->method('resolveEnabledShortUrl');
$this->requestTracker->expects($this->never())->method('trackIfApplicable');
$this->redirectionBuilder->expects($this->never())->method('buildShortUrlRedirect');
$this->redirectResponseHelper->expects($this->never())->method('buildRedirectResponse');
$this->handler->expects($this->once())->method('handle');
$this->middleware($options)->process($request, $this->handler->reveal()); $this->middleware($options)->process($request, $this->handler);
$this->handler->handle($request)->shouldHaveBeenCalledOnce();
$this->resolver->resolveEnabledShortUrl(Argument::cetera())->shouldNotHaveBeenCalled();
$this->requestTracker->trackIfApplicable(Argument::cetera())->shouldNotHaveBeenCalled();
$this->redirectionBuilder->buildShortUrlRedirect(Argument::cetera())->shouldNotHaveBeenCalled();
$this->redirectResponseHelper->buildRedirectResponse(Argument::cetera())->shouldNotHaveBeenCalled();
} }
public function provideNonRedirectingRequests(): iterable public function provideNonRedirectingRequests(): iterable
@ -89,7 +84,7 @@ class ExtraPathRedirectMiddlewareTest extends TestCase
RouteResult::class, RouteResult::class,
RouteResult::fromRoute(new Route( RouteResult::fromRoute(new Route(
'/foo', '/foo',
$this->prophesize(MiddlewareInterface::class)->reveal(), $this->createMock(MiddlewareInterface::class),
['GET'], ['GET'],
RedirectAction::class, RedirectAction::class,
)), )),
@ -115,22 +110,20 @@ class ExtraPathRedirectMiddlewareTest extends TestCase
): void { ): void {
$options = new UrlShortenerOptions(appendExtraPath: true, multiSegmentSlugsEnabled: $multiSegmentEnabled); $options = new UrlShortenerOptions(appendExtraPath: true, multiSegmentSlugsEnabled: $multiSegmentEnabled);
$type = $this->prophesize(NotFoundType::class); $type = $this->createMock(NotFoundType::class);
$type->isRegularNotFound()->willReturn(true); $type->method('isRegularNotFound')->willReturn(true);
$type->isInvalidShortUrl()->willReturn(true); $type->method('isInvalidShortUrl')->willReturn(true);
$request = ServerRequestFactory::fromGlobals()->withAttribute(NotFoundType::class, $type->reveal()) $request = ServerRequestFactory::fromGlobals()->withAttribute(NotFoundType::class, $type)
->withUri(new Uri('/shortCode/bar/baz')); ->withUri(new Uri('/shortCode/bar/baz'));
$resolve = $this->resolver->resolveEnabledShortUrl( $this->resolver->expects($this->exactly($expectedResolveCalls))->method('resolveEnabledShortUrl')->with(
Argument::that(fn (ShortUrlIdentifier $identifier) => str_starts_with($identifier->shortCode, 'shortCode')), $this->callback(fn (ShortUrlIdentifier $id) => str_starts_with($id->shortCode, 'shortCode')),
)->willThrow(ShortUrlNotFoundException::class); )->willThrowException(ShortUrlNotFoundException::fromNotFound(ShortUrlIdentifier::fromShortCodeAndDomain('')));
$this->requestTracker->expects($this->never())->method('trackIfApplicable');
$this->redirectionBuilder->expects($this->never())->method('buildShortUrlRedirect');
$this->redirectResponseHelper->expects($this->never())->method('buildRedirectResponse');
$this->middleware($options)->process($request, $this->handler->reveal()); $this->middleware($options)->process($request, $this->handler);
$resolve->shouldHaveBeenCalledTimes($expectedResolveCalls);
$this->requestTracker->trackIfApplicable(Argument::cetera())->shouldNotHaveBeenCalled();
$this->redirectionBuilder->buildShortUrlRedirect(Argument::cetera())->shouldNotHaveBeenCalled();
$this->redirectResponseHelper->buildRedirectResponse(Argument::cetera())->shouldNotHaveBeenCalled();
} }
/** /**
@ -144,18 +137,17 @@ class ExtraPathRedirectMiddlewareTest extends TestCase
): void { ): void {
$options = new UrlShortenerOptions(appendExtraPath: true, multiSegmentSlugsEnabled: $multiSegmentEnabled); $options = new UrlShortenerOptions(appendExtraPath: true, multiSegmentSlugsEnabled: $multiSegmentEnabled);
$type = $this->prophesize(NotFoundType::class); $type = $this->createMock(NotFoundType::class);
$type->isRegularNotFound()->willReturn(true); $type->method('isRegularNotFound')->willReturn(true);
$type->isInvalidShortUrl()->willReturn(true); $type->method('isInvalidShortUrl')->willReturn(true);
$request = ServerRequestFactory::fromGlobals()->withAttribute(NotFoundType::class, $type->reveal()) $request = ServerRequestFactory::fromGlobals()->withAttribute(NotFoundType::class, $type)
->withUri(new Uri('https://doma.in/shortCode/bar/baz')); ->withUri(new Uri('https://doma.in/shortCode/bar/baz'));
$shortUrl = ShortUrl::withLongUrl(''); $shortUrl = ShortUrl::withLongUrl('');
$identifier = Argument::that(
fn (ShortUrlIdentifier $identifier) => str_starts_with($identifier->shortCode, 'shortCode'),
);
$currentIteration = 1; $currentIteration = 1;
$resolve = $this->resolver->resolveEnabledShortUrl($identifier)->will( $this->resolver->expects($this->exactly($expectedResolveCalls))->method('resolveEnabledShortUrl')->with(
$this->callback(fn (ShortUrlIdentifier $id) => str_starts_with($id->shortCode, 'shortCode')),
)->willReturnCallback(
function () use ($shortUrl, &$currentIteration, $expectedResolveCalls): ShortUrl { function () use ($shortUrl, &$currentIteration, $expectedResolveCalls): ShortUrl {
if ($expectedResolveCalls === $currentIteration) { if ($expectedResolveCalls === $currentIteration) {
return $shortUrl; return $shortUrl;
@ -165,18 +157,17 @@ class ExtraPathRedirectMiddlewareTest extends TestCase
throw ShortUrlNotFoundException::fromNotFound(ShortUrlIdentifier::fromShortUrl($shortUrl)); throw ShortUrlNotFoundException::fromNotFound(ShortUrlIdentifier::fromShortUrl($shortUrl));
}, },
); );
$buildLongUrl = $this->redirectionBuilder->buildShortUrlRedirect($shortUrl, [], $expectedExtraPath) $this->redirectionBuilder->expects($this->once())->method('buildShortUrlRedirect')->with(
->willReturn('the_built_long_url'); $shortUrl,
$buildResp = $this->redirectResponseHelper->buildRedirectResponse('the_built_long_url')->willReturn( [],
new RedirectResponse(''), $expectedExtraPath,
); )->willReturn('the_built_long_url');
$this->redirectResponseHelper->expects($this->once())->method('buildRedirectResponse')->with(
'the_built_long_url',
)->willReturn(new RedirectResponse(''));
$this->requestTracker->expects($this->once())->method('trackIfApplicable')->with($shortUrl, $request);
$this->middleware($options)->process($request, $this->handler->reveal()); $this->middleware($options)->process($request, $this->handler);
$resolve->shouldHaveBeenCalledTimes($expectedResolveCalls);
$buildLongUrl->shouldHaveBeenCalledOnce();
$buildResp->shouldHaveBeenCalledOnce();
$this->requestTracker->trackIfApplicable($shortUrl, $request)->shouldHaveBeenCalledOnce();
} }
public function provideResolves(): iterable public function provideResolves(): iterable
@ -188,10 +179,10 @@ class ExtraPathRedirectMiddlewareTest extends TestCase
private function middleware(?UrlShortenerOptions $options = null): ExtraPathRedirectMiddleware private function middleware(?UrlShortenerOptions $options = null): ExtraPathRedirectMiddleware
{ {
return new ExtraPathRedirectMiddleware( return new ExtraPathRedirectMiddleware(
$this->resolver->reveal(), $this->resolver,
$this->requestTracker->reveal(), $this->requestTracker,
$this->redirectionBuilder->reveal(), $this->redirectionBuilder,
$this->redirectResponseHelper->reveal(), $this->redirectResponseHelper,
$options ?? new UrlShortenerOptions(appendExtraPath: true), $options ?? new UrlShortenerOptions(appendExtraPath: true),
); );
} }

View file

@ -7,10 +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\MockObject\MockObject;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Prophecy\Argument;
use Prophecy\PhpUnit\ProphecyTrait;
use Prophecy\Prophecy\ObjectProphecy;
use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface; use Psr\Http\Server\RequestHandlerInterface;
use Shlinkio\Shlink\Core\Options\UrlShortenerOptions; use Shlinkio\Shlink\Core\Options\UrlShortenerOptions;
@ -21,13 +19,11 @@ use function Functional\const_function;
class TrimTrailingSlashMiddlewareTest extends TestCase class TrimTrailingSlashMiddlewareTest extends TestCase
{ {
use ProphecyTrait; private MockObject $requestHandler;
private ObjectProphecy $requestHandler;
protected function setUp(): void protected function setUp(): void
{ {
$this->requestHandler = $this->prophesize(RequestHandlerInterface::class); $this->requestHandler = $this->createMock(RequestHandlerInterface::class);
} }
/** /**
@ -40,9 +36,11 @@ class TrimTrailingSlashMiddlewareTest extends TestCase
callable $assertions, callable $assertions,
): void { ): void {
$arg = compose($assertions, const_function(true)); $arg = compose($assertions, const_function(true));
$this->requestHandler->expects($this->once())->method('handle')->with($this->callback($arg))->willReturn(
new Response(),
);
$this->requestHandler->handle(Argument::that($arg))->willReturn(new Response()); $this->middleware($trailingSlashEnabled)->process($inputRequest, $this->requestHandler);
$this->middleware($trailingSlashEnabled)->process($inputRequest, $this->requestHandler->reveal());
} }
public function provideRequests(): iterable public function provideRequests(): iterable

View file

@ -5,9 +5,8 @@ declare(strict_types=1);
namespace ShlinkioTest\Shlink\Core\ShortUrl\Paginator\Adapter; namespace ShlinkioTest\Shlink\Core\ShortUrl\Paginator\Adapter;
use Cake\Chronos\Chronos; use Cake\Chronos\Chronos;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Prophecy\PhpUnit\ProphecyTrait;
use Prophecy\Prophecy\ObjectProphecy;
use Shlinkio\Shlink\Core\ShortUrl\Model\ShortUrlsParams; use Shlinkio\Shlink\Core\ShortUrl\Model\ShortUrlsParams;
use Shlinkio\Shlink\Core\ShortUrl\Model\TagsMode; use Shlinkio\Shlink\Core\ShortUrl\Model\TagsMode;
use Shlinkio\Shlink\Core\ShortUrl\Paginator\Adapter\ShortUrlRepositoryAdapter; use Shlinkio\Shlink\Core\ShortUrl\Paginator\Adapter\ShortUrlRepositoryAdapter;
@ -18,13 +17,11 @@ use Shlinkio\Shlink\Rest\Entity\ApiKey;
class ShortUrlRepositoryAdapterTest extends TestCase class ShortUrlRepositoryAdapterTest extends TestCase
{ {
use ProphecyTrait; private MockObject $repo;
private ObjectProphecy $repo;
protected function setUp(): void protected function setUp(): void
{ {
$this->repo = $this->prophesize(ShortUrlRepositoryInterface::class); $this->repo = $this->createMock(ShortUrlRepositoryInterface::class);
} }
/** /**
@ -45,13 +42,14 @@ class ShortUrlRepositoryAdapterTest extends TestCase
'endDate' => $endDate, 'endDate' => $endDate,
'orderBy' => $orderBy, 'orderBy' => $orderBy,
]); ]);
$adapter = new ShortUrlRepositoryAdapter($this->repo->reveal(), $params, null); $adapter = new ShortUrlRepositoryAdapter($this->repo, $params, null);
$orderBy = $params->orderBy(); $orderBy = $params->orderBy();
$dateRange = $params->dateRange(); $dateRange = $params->dateRange();
$this->repo->findList( $this->repo->expects($this->once())->method('findList')->with(
new ShortUrlsListFiltering(10, 5, $orderBy, $searchTerm, $tags, TagsMode::ANY, $dateRange), new ShortUrlsListFiltering(10, 5, $orderBy, $searchTerm, $tags, TagsMode::ANY, $dateRange),
)->shouldBeCalledOnce(); );
$adapter->getSlice(5, 10); $adapter->getSlice(5, 10);
} }
@ -72,12 +70,12 @@ class ShortUrlRepositoryAdapterTest extends TestCase
'endDate' => $endDate, 'endDate' => $endDate,
]); ]);
$apiKey = ApiKey::create(); $apiKey = ApiKey::create();
$adapter = new ShortUrlRepositoryAdapter($this->repo->reveal(), $params, $apiKey); $adapter = new ShortUrlRepositoryAdapter($this->repo, $params, $apiKey);
$dateRange = $params->dateRange(); $dateRange = $params->dateRange();
$this->repo->countList( $this->repo->expects($this->once())->method('countList')->with(
new ShortUrlsCountFiltering($searchTerm, $tags, TagsMode::ANY, $dateRange, $apiKey), new ShortUrlsCountFiltering($searchTerm, $tags, TagsMode::ANY, $dateRange, $apiKey),
)->shouldBeCalledOnce(); );
$adapter->getNbResults(); $adapter->getNbResults();
} }

View file

@ -6,10 +6,8 @@ namespace ShlinkioTest\Shlink\Core\ShortUrl\Resolver;
use Doctrine\Common\EventManager; use Doctrine\Common\EventManager;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Prophecy\Argument;
use Prophecy\PhpUnit\ProphecyTrait;
use Prophecy\Prophecy\ObjectProphecy;
use Shlinkio\Shlink\Core\Domain\Entity\Domain; use Shlinkio\Shlink\Core\Domain\Entity\Domain;
use Shlinkio\Shlink\Core\Domain\Repository\DomainRepositoryInterface; use Shlinkio\Shlink\Core\Domain\Repository\DomainRepositoryInterface;
use Shlinkio\Shlink\Core\ShortUrl\Resolver\PersistenceShortUrlRelationResolver; use Shlinkio\Shlink\Core\ShortUrl\Resolver\PersistenceShortUrlRelationResolver;
@ -20,26 +18,22 @@ use function count;
class PersistenceShortUrlRelationResolverTest extends TestCase class PersistenceShortUrlRelationResolverTest extends TestCase
{ {
use ProphecyTrait;
private PersistenceShortUrlRelationResolver $resolver; private PersistenceShortUrlRelationResolver $resolver;
private ObjectProphecy $em; private MockObject $em;
protected function setUp(): void protected function setUp(): void
{ {
$this->em = $this->prophesize(EntityManagerInterface::class); $this->em = $this->createMock(EntityManagerInterface::class);
$this->em->getEventManager()->willReturn(new EventManager()); $this->em->method('getEventManager')->willReturn(new EventManager());
$this->resolver = new PersistenceShortUrlRelationResolver($this->em->reveal()); $this->resolver = new PersistenceShortUrlRelationResolver($this->em);
} }
/** @test */ /** @test */
public function returnsEmptyWhenNoDomainIsProvided(): void public function returnsEmptyWhenNoDomainIsProvided(): void
{ {
$getRepository = $this->em->getRepository(Domain::class); $this->em->expects($this->never())->method('getRepository')->with(Domain::class);
self::assertNull($this->resolver->resolveDomain(null)); self::assertNull($this->resolver->resolveDomain(null));
$getRepository->shouldNotHaveBeenCalled();
} }
/** /**
@ -48,9 +42,9 @@ class PersistenceShortUrlRelationResolverTest extends TestCase
*/ */
public function findsOrCreatesDomainWhenValueIsProvided(?Domain $foundDomain, string $authority): void public function findsOrCreatesDomainWhenValueIsProvided(?Domain $foundDomain, string $authority): void
{ {
$repo = $this->prophesize(DomainRepositoryInterface::class); $repo = $this->createMock(DomainRepositoryInterface::class);
$findDomain = $repo->findOneBy(['authority' => $authority])->willReturn($foundDomain); $repo->expects($this->once())->method('findOneBy')->with(['authority' => $authority])->willReturn($foundDomain);
$getRepository = $this->em->getRepository(Domain::class)->willReturn($repo->reveal()); $this->em->expects($this->once())->method('getRepository')->with(Domain::class)->willReturn($repo);
$result = $this->resolver->resolveDomain($authority); $result = $this->resolver->resolveDomain($authority);
@ -59,8 +53,6 @@ class PersistenceShortUrlRelationResolverTest extends TestCase
} }
self::assertInstanceOf(Domain::class, $result); self::assertInstanceOf(Domain::class, $result);
self::assertEquals($authority, $result->getAuthority()); self::assertEquals($authority, $result->getAuthority());
$findDomain->shouldHaveBeenCalledOnce();
$getRepository->shouldHaveBeenCalledOnce();
} }
public function provideFoundDomains(): iterable public function provideFoundDomains(): iterable
@ -79,21 +71,22 @@ class PersistenceShortUrlRelationResolverTest extends TestCase
{ {
$expectedPersistedTags = count($expectedTags); $expectedPersistedTags = count($expectedTags);
$tagRepo = $this->prophesize(TagRepositoryInterface::class); $tagRepo = $this->createMock(TagRepositoryInterface::class);
$findTag = $tagRepo->findOneBy(Argument::type('array'))->will(function (array $args): ?Tag { $tagRepo->expects($this->exactly($expectedPersistedTags))->method('findOneBy')->with(
['name' => $name] = $args[0]; $this->isType('array'),
)->willReturnCallback(function (array $criteria): ?Tag {
['name' => $name] = $criteria;
return $name === 'foo' ? new Tag($name) : null; return $name === 'foo' ? new Tag($name) : null;
}); });
$getRepo = $this->em->getRepository(Tag::class)->willReturn($tagRepo->reveal()); $this->em->expects($this->once())->method('getRepository')->with(Tag::class)->willReturn($tagRepo);
$persist = $this->em->persist(Argument::type(Tag::class)); $this->em->expects($this->exactly($expectedPersistedTags))->method('persist')->with(
$this->isInstanceOf(Tag::class),
);
$result = $this->resolver->resolveTags($tags); $result = $this->resolver->resolveTags($tags);
self::assertCount($expectedPersistedTags, $result); self::assertCount($expectedPersistedTags, $result);
self::assertEquals($expectedTags, $result->toArray()); self::assertEquals($expectedTags, $result->toArray());
$findTag->shouldHaveBeenCalledTimes($expectedPersistedTags);
$getRepo->shouldHaveBeenCalledOnce();
$persist->shouldHaveBeenCalledTimes($expectedPersistedTags);
} }
public function provideTags(): iterable public function provideTags(): iterable
@ -105,25 +98,20 @@ class PersistenceShortUrlRelationResolverTest extends TestCase
/** @test */ /** @test */
public function returnsEmptyCollectionWhenProvidingEmptyListOfTags(): void public function returnsEmptyCollectionWhenProvidingEmptyListOfTags(): void
{ {
$tagRepo = $this->prophesize(TagRepositoryInterface::class); $this->em->expects($this->never())->method('getRepository')->with(Tag::class);
$findTag = $tagRepo->findOneBy(Argument::type('array'))->willReturn(null); $this->em->expects($this->never())->method('persist');
$getRepo = $this->em->getRepository(Tag::class)->willReturn($tagRepo->reveal());
$persist = $this->em->persist(Argument::type(Tag::class));
$result = $this->resolver->resolveTags([]); $result = $this->resolver->resolveTags([]);
self::assertEmpty($result); self::assertEmpty($result);
$findTag->shouldNotHaveBeenCalled();
$getRepo->shouldNotHaveBeenCalled();
$persist->shouldNotHaveBeenCalled();
} }
/** @test */ /** @test */
public function newDomainsAreMemoizedUntilStateIsCleared(): void public function newDomainsAreMemoizedUntilStateIsCleared(): void
{ {
$repo = $this->prophesize(DomainRepositoryInterface::class); $repo = $this->createMock(DomainRepositoryInterface::class);
$repo->findOneBy(Argument::type('array'))->willReturn(null); $repo->expects($this->exactly(3))->method('findOneBy')->with($this->isType('array'))->willReturn(null);
$this->em->getRepository(Domain::class)->willReturn($repo->reveal()); $this->em->method('getRepository')->with(Domain::class)->willReturn($repo);
$authority = 'foo.com'; $authority = 'foo.com';
$domain1 = $this->resolver->resolveDomain($authority); $domain1 = $this->resolver->resolveDomain($authority);
@ -140,11 +128,9 @@ class PersistenceShortUrlRelationResolverTest extends TestCase
/** @test */ /** @test */
public function newTagsAreMemoizedUntilStateIsCleared(): void public function newTagsAreMemoizedUntilStateIsCleared(): void
{ {
$tagRepo = $this->prophesize(TagRepositoryInterface::class); $tagRepo = $this->createMock(TagRepositoryInterface::class);
$tagRepo->findOneBy(Argument::type('array'))->willReturn(null); $tagRepo->expects($this->exactly(6))->method('findOneBy')->with($this->isType('array'))->willReturn(null);
$this->em->getRepository(Tag::class)->willReturn($tagRepo->reveal()); $this->em->method('getRepository')->with(Tag::class)->willReturn($tagRepo);
$this->em->persist(Argument::type(Tag::class))->will(function (): void {
});
$tags = ['foo', 'bar']; $tags = ['foo', 'bar'];
[$foo1, $bar1] = $this->resolver->resolveTags($tags); [$foo1, $bar1] = $this->resolver->resolveTags($tags);

View file

@ -7,9 +7,8 @@ namespace ShlinkioTest\Shlink\Core\ShortUrl;
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\MockObject\MockObject;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Prophecy\PhpUnit\ProphecyTrait;
use Prophecy\Prophecy\ObjectProphecy;
use Shlinkio\Shlink\Core\Exception\ShortUrlNotFoundException; use Shlinkio\Shlink\Core\Exception\ShortUrlNotFoundException;
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;
@ -27,15 +26,16 @@ use function range;
class ShortUrlResolverTest extends TestCase class ShortUrlResolverTest extends TestCase
{ {
use ApiKeyHelpersTrait; use ApiKeyHelpersTrait;
use ProphecyTrait;
private ShortUrlResolver $urlResolver; private ShortUrlResolver $urlResolver;
private ObjectProphecy $em; private MockObject $em;
private MockObject $repo;
protected function setUp(): void protected function setUp(): void
{ {
$this->em = $this->prophesize(EntityManagerInterface::class); $this->em = $this->createMock(EntityManagerInterface::class);
$this->urlResolver = new ShortUrlResolver($this->em->reveal()); $this->repo = $this->createMock(ShortUrlRepositoryInterface::class);
$this->urlResolver = new ShortUrlResolver($this->em);
} }
/** /**
@ -48,15 +48,14 @@ class ShortUrlResolverTest extends TestCase
$shortCode = $shortUrl->getShortCode(); $shortCode = $shortUrl->getShortCode();
$identifier = ShortUrlIdentifier::fromShortCodeAndDomain($shortCode); $identifier = ShortUrlIdentifier::fromShortCodeAndDomain($shortCode);
$repo = $this->prophesize(ShortUrlRepositoryInterface::class); $this->repo->expects($this->once())->method('findOne')->with($identifier, $apiKey?->spec())->willReturn(
$findOne = $repo->findOne($identifier, $apiKey?->spec())->willReturn($shortUrl); $shortUrl,
$getRepo = $this->em->getRepository(ShortUrl::class)->willReturn($repo->reveal()); );
$this->em->expects($this->once())->method('getRepository')->with(ShortUrl::class)->willReturn($this->repo);
$result = $this->urlResolver->resolveShortUrl($identifier, $apiKey); $result = $this->urlResolver->resolveShortUrl($identifier, $apiKey);
self::assertSame($shortUrl, $result); self::assertSame($shortUrl, $result);
$findOne->shouldHaveBeenCalledOnce();
$getRepo->shouldHaveBeenCalledOnce();
} }
/** /**
@ -68,13 +67,10 @@ class ShortUrlResolverTest extends TestCase
$shortCode = 'abc123'; $shortCode = 'abc123';
$identifier = ShortUrlIdentifier::fromShortCodeAndDomain($shortCode); $identifier = ShortUrlIdentifier::fromShortCodeAndDomain($shortCode);
$repo = $this->prophesize(ShortUrlRepositoryInterface::class); $this->repo->expects($this->once())->method('findOne')->with($identifier, $apiKey?->spec())->willReturn(null);
$findOne = $repo->findOne($identifier, $apiKey?->spec())->willReturn(null); $this->em->expects($this->once())->method('getRepository')->with(ShortUrl::class)->willReturn($this->repo);
$getRepo = $this->em->getRepository(ShortUrl::class)->willReturn($repo->reveal(), $apiKey);
$this->expectException(ShortUrlNotFoundException::class); $this->expectException(ShortUrlNotFoundException::class);
$findOne->shouldBeCalledOnce();
$getRepo->shouldBeCalledOnce();
$this->urlResolver->resolveShortUrl($identifier, $apiKey); $this->urlResolver->resolveShortUrl($identifier, $apiKey);
} }
@ -85,17 +81,14 @@ class ShortUrlResolverTest extends TestCase
$shortUrl = ShortUrl::withLongUrl('expected_url'); $shortUrl = ShortUrl::withLongUrl('expected_url');
$shortCode = $shortUrl->getShortCode(); $shortCode = $shortUrl->getShortCode();
$repo = $this->prophesize(ShortUrlRepositoryInterface::class); $this->repo->expects($this->once())->method('findOneWithDomainFallback')->with(
$findOneByShortCode = $repo->findOneWithDomainFallback(
ShortUrlIdentifier::fromShortCodeAndDomain($shortCode), ShortUrlIdentifier::fromShortCodeAndDomain($shortCode),
)->willReturn($shortUrl); )->willReturn($shortUrl);
$getRepo = $this->em->getRepository(ShortUrl::class)->willReturn($repo->reveal()); $this->em->expects($this->once())->method('getRepository')->with(ShortUrl::class)->willReturn($this->repo);
$result = $this->urlResolver->resolveEnabledShortUrl(ShortUrlIdentifier::fromShortCodeAndDomain($shortCode)); $result = $this->urlResolver->resolveEnabledShortUrl(ShortUrlIdentifier::fromShortCodeAndDomain($shortCode));
self::assertSame($shortUrl, $result); self::assertSame($shortUrl, $result);
$findOneByShortCode->shouldHaveBeenCalledOnce();
$getRepo->shouldHaveBeenCalledOnce();
} }
/** /**
@ -106,15 +99,12 @@ class ShortUrlResolverTest extends TestCase
{ {
$shortCode = $shortUrl->getShortCode(); $shortCode = $shortUrl->getShortCode();
$repo = $this->prophesize(ShortUrlRepositoryInterface::class); $this->repo->expects($this->once())->method('findOneWithDomainFallback')->with(
$findOneByShortCode = $repo->findOneWithDomainFallback(
ShortUrlIdentifier::fromShortCodeAndDomain($shortCode), ShortUrlIdentifier::fromShortCodeAndDomain($shortCode),
)->willReturn($shortUrl); )->willReturn($shortUrl);
$getRepo = $this->em->getRepository(ShortUrl::class)->willReturn($repo->reveal()); $this->em->expects($this->once())->method('getRepository')->with(ShortUrl::class)->willReturn($this->repo);
$this->expectException(ShortUrlNotFoundException::class); $this->expectException(ShortUrlNotFoundException::class);
$findOneByShortCode->shouldBeCalledOnce();
$getRepo->shouldBeCalledOnce();
$this->urlResolver->resolveEnabledShortUrl(ShortUrlIdentifier::fromShortCodeAndDomain($shortCode)); $this->urlResolver->resolveEnabledShortUrl(ShortUrlIdentifier::fromShortCodeAndDomain($shortCode));
} }

View file

@ -6,10 +6,8 @@ namespace ShlinkioTest\Shlink\Core\ShortUrl;
use Cake\Chronos\Chronos; use Cake\Chronos\Chronos;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Prophecy\Argument;
use Prophecy\PhpUnit\ProphecyTrait;
use Prophecy\Prophecy\ObjectProphecy;
use Shlinkio\Shlink\Core\ShortUrl\Entity\ShortUrl; use Shlinkio\Shlink\Core\ShortUrl\Entity\ShortUrl;
use Shlinkio\Shlink\Core\ShortUrl\Helper\ShortUrlTitleResolutionHelperInterface; use Shlinkio\Shlink\Core\ShortUrl\Helper\ShortUrlTitleResolutionHelperInterface;
use Shlinkio\Shlink\Core\ShortUrl\Model\ShortUrlEdition; use Shlinkio\Shlink\Core\ShortUrl\Model\ShortUrlEdition;
@ -27,26 +25,25 @@ use function count;
class ShortUrlServiceTest extends TestCase class ShortUrlServiceTest extends TestCase
{ {
use ApiKeyHelpersTrait; use ApiKeyHelpersTrait;
use ProphecyTrait;
private ShortUrlService $service; private ShortUrlService $service;
private ObjectProphecy $em; private MockObject $em;
private ObjectProphecy $urlResolver; private MockObject $urlResolver;
private ObjectProphecy $titleResolutionHelper; private MockObject $titleResolutionHelper;
protected function setUp(): void protected function setUp(): void
{ {
$this->em = $this->prophesize(EntityManagerInterface::class); $this->em = $this->createMock(EntityManagerInterface::class);
$this->em->persist(Argument::any())->willReturn(null); $this->em->method('persist')->willReturn(null);
$this->em->flush()->willReturn(null); $this->em->method('flush')->willReturn(null);
$this->urlResolver = $this->prophesize(ShortUrlResolverInterface::class); $this->urlResolver = $this->createMock(ShortUrlResolverInterface::class);
$this->titleResolutionHelper = $this->prophesize(ShortUrlTitleResolutionHelperInterface::class); $this->titleResolutionHelper = $this->createMock(ShortUrlTitleResolutionHelperInterface::class);
$this->service = new ShortUrlService( $this->service = new ShortUrlService(
$this->em->reveal(), $this->em,
$this->urlResolver->reveal(), $this->urlResolver,
$this->titleResolutionHelper->reveal(), $this->titleResolutionHelper,
new SimpleShortUrlRelationResolver(), new SimpleShortUrlRelationResolver(),
); );
} }
@ -64,10 +61,10 @@ class ShortUrlServiceTest extends TestCase
ShortUrl::createEmpty(), ShortUrl::createEmpty(),
]; ];
$repo = $this->prophesize(ShortUrlRepository::class); $repo = $this->createMock(ShortUrlRepository::class);
$repo->findList(Argument::cetera())->willReturn($list)->shouldBeCalledOnce(); $repo->expects($this->once())->method('findList')->willReturn($list);
$repo->countList(Argument::cetera())->willReturn(count($list))->shouldBeCalledOnce(); $repo->expects($this->once())->method('countList')->willReturn(count($list));
$this->em->getRepository(ShortUrl::class)->willReturn($repo->reveal()); $this->em->method('getRepository')->with(ShortUrl::class)->willReturn($repo);
$paginator = $this->service->listShortUrls(ShortUrlsParams::emptyInstance(), $apiKey); $paginator = $this->service->listShortUrls(ShortUrlsParams::emptyInstance(), $apiKey);
@ -87,15 +84,15 @@ class ShortUrlServiceTest extends TestCase
$originalLongUrl = 'originalLongUrl'; $originalLongUrl = 'originalLongUrl';
$shortUrl = ShortUrl::withLongUrl($originalLongUrl); $shortUrl = ShortUrl::withLongUrl($originalLongUrl);
$findShortUrl = $this->urlResolver->resolveShortUrl( $this->urlResolver->expects($this->once())->method('resolveShortUrl')->with(
ShortUrlIdentifier::fromShortCodeAndDomain('abc123'), ShortUrlIdentifier::fromShortCodeAndDomain('abc123'),
$apiKey, $apiKey,
)->willReturn($shortUrl); )->willReturn($shortUrl);
$flush = $this->em->flush()->willReturn(null);
$processTitle = $this->titleResolutionHelper->processTitleAndValidateUrl($shortUrlEdit)->willReturn( $this->titleResolutionHelper->expects($this->exactly($expectedValidateCalls))
$shortUrlEdit, ->method('processTitleAndValidateUrl')
); ->with($shortUrlEdit)
->willReturn($shortUrlEdit);
$result = $this->service->updateShortUrl( $result = $this->service->updateShortUrl(
ShortUrlIdentifier::fromShortCodeAndDomain('abc123'), ShortUrlIdentifier::fromShortCodeAndDomain('abc123'),
@ -108,9 +105,6 @@ class ShortUrlServiceTest extends TestCase
self::assertEquals($shortUrlEdit->validUntil(), $shortUrl->getValidUntil()); self::assertEquals($shortUrlEdit->validUntil(), $shortUrl->getValidUntil());
self::assertEquals($shortUrlEdit->maxVisits(), $shortUrl->getMaxVisits()); self::assertEquals($shortUrlEdit->maxVisits(), $shortUrl->getMaxVisits());
self::assertEquals($shortUrlEdit->longUrl() ?? $originalLongUrl, $shortUrl->getLongUrl()); self::assertEquals($shortUrlEdit->longUrl() ?? $originalLongUrl, $shortUrl->getLongUrl());
$findShortUrl->shouldHaveBeenCalled();
$flush->shouldHaveBeenCalled();
$processTitle->shouldHaveBeenCalledTimes($expectedValidateCalls);
} }
public function provideShortUrlEdits(): iterable public function provideShortUrlEdits(): iterable

View file

@ -5,11 +5,9 @@ declare(strict_types=1);
namespace ShlinkioTest\Shlink\Core\ShortUrl; namespace ShlinkioTest\Shlink\Core\ShortUrl;
use Cake\Chronos\Chronos; use Cake\Chronos\Chronos;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManager;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Prophecy\Argument;
use Prophecy\PhpUnit\ProphecyTrait;
use Prophecy\Prophecy\ObjectProphecy;
use Psr\EventDispatcher\EventDispatcherInterface; use Psr\EventDispatcher\EventDispatcherInterface;
use Shlinkio\Shlink\Core\Exception\NonUniqueSlugException; use Shlinkio\Shlink\Core\Exception\NonUniqueSlugException;
use Shlinkio\Shlink\Core\ShortUrl\Entity\ShortUrl; use Shlinkio\Shlink\Core\ShortUrl\Entity\ShortUrl;
@ -22,42 +20,29 @@ use Shlinkio\Shlink\Core\ShortUrl\UrlShortener;
class UrlShortenerTest extends TestCase class UrlShortenerTest extends TestCase
{ {
use ProphecyTrait;
private UrlShortener $urlShortener; private UrlShortener $urlShortener;
private ObjectProphecy $em; private MockObject $em;
private ObjectProphecy $titleResolutionHelper; private MockObject $titleResolutionHelper;
private ObjectProphecy $shortCodeHelper; private MockObject $shortCodeHelper;
protected function setUp(): void protected function setUp(): void
{ {
$this->titleResolutionHelper = $this->prophesize(ShortUrlTitleResolutionHelperInterface::class); $this->titleResolutionHelper = $this->createMock(ShortUrlTitleResolutionHelperInterface::class);
$this->titleResolutionHelper->processTitleAndValidateUrl(Argument::cetera())->willReturnArgument(); $this->shortCodeHelper = $this->createMock(ShortCodeUniquenessHelperInterface::class);
$this->em = $this->prophesize(EntityManagerInterface::class); // FIXME Should use the interface, but it doe snot define wrapInTransaction explicitly
$this->em->persist(Argument::any())->will(function ($arguments): void { $this->em = $this->createMock(EntityManager::class);
/** @var ShortUrl $shortUrl */ $this->em->method('persist')->willReturnCallback(fn (ShortUrl $shortUrl) => $shortUrl->setId('10'));
[$shortUrl] = $arguments; $this->em->method('wrapInTransaction')->with($this->isType('callable'))->willReturnCallback(
$shortUrl->setId('10'); fn (callable $callback) => $callback(),
}); );
$this->em->wrapInTransaction(Argument::type('callable'))->will(function (array $args) {
/** @var callable $callback */
[$callback] = $args;
return $callback();
});
$repo = $this->prophesize(ShortUrlRepository::class);
$this->em->getRepository(ShortUrl::class)->willReturn($repo->reveal());
$this->shortCodeHelper = $this->prophesize(ShortCodeUniquenessHelperInterface::class);
$this->shortCodeHelper->ensureShortCodeUniqueness(Argument::cetera())->willReturn(true);
$this->urlShortener = new UrlShortener( $this->urlShortener = new UrlShortener(
$this->titleResolutionHelper->reveal(), $this->titleResolutionHelper,
$this->em->reveal(), $this->em,
new SimpleShortUrlRelationResolver(), new SimpleShortUrlRelationResolver(),
$this->shortCodeHelper->reveal(), $this->shortCodeHelper,
$this->prophesize(EventDispatcherInterface::class)->reveal(), $this->createMock(EventDispatcherInterface::class),
); );
} }
@ -66,23 +51,31 @@ class UrlShortenerTest extends TestCase
{ {
$longUrl = 'http://foobar.com/12345/hello?foo=bar'; $longUrl = 'http://foobar.com/12345/hello?foo=bar';
$meta = ShortUrlCreation::fromRawData(['longUrl' => $longUrl]); $meta = ShortUrlCreation::fromRawData(['longUrl' => $longUrl]);
$this->titleResolutionHelper->expects($this->once())->method('processTitleAndValidateUrl')->with(
$meta,
)->willReturnArgument(0);
$this->shortCodeHelper->method('ensureShortCodeUniqueness')->willReturn(true);
$shortUrl = $this->urlShortener->shorten($meta); $shortUrl = $this->urlShortener->shorten($meta);
self::assertEquals($longUrl, $shortUrl->getLongUrl()); self::assertEquals($longUrl, $shortUrl->getLongUrl());
$this->titleResolutionHelper->processTitleAndValidateUrl($meta)->shouldHaveBeenCalledOnce();
} }
/** @test */ /** @test */
public function exceptionIsThrownWhenNonUniqueSlugIsProvided(): void public function exceptionIsThrownWhenNonUniqueSlugIsProvided(): void
{ {
$ensureUniqueness = $this->shortCodeHelper->ensureShortCodeUniqueness(Argument::cetera())->willReturn(false); $meta = ShortUrlCreation::fromRawData(
['customSlug' => 'custom-slug', 'longUrl' => 'http://foobar.com/12345/hello?foo=bar'],
);
$this->shortCodeHelper->expects($this->once())->method('ensureShortCodeUniqueness')->willReturn(false);
$this->titleResolutionHelper->expects($this->once())->method('processTitleAndValidateUrl')->with(
$meta,
)->willReturnArgument(0);
$ensureUniqueness->shouldBeCalledOnce();
$this->expectException(NonUniqueSlugException::class); $this->expectException(NonUniqueSlugException::class);
$this->urlShortener->shorten(ShortUrlCreation::fromRawData( $this->urlShortener->shorten($meta);
['customSlug' => 'custom-slug', 'longUrl' => 'http://foobar.com/12345/hello?foo=bar'],
));
} }
/** /**
@ -91,16 +84,14 @@ class UrlShortenerTest extends TestCase
*/ */
public function existingShortUrlIsReturnedWhenRequested(ShortUrlCreation $meta, ShortUrl $expected): void public function existingShortUrlIsReturnedWhenRequested(ShortUrlCreation $meta, ShortUrl $expected): void
{ {
$repo = $this->prophesize(ShortUrlRepository::class); $repo = $this->createMock(ShortUrlRepository::class);
$findExisting = $repo->findOneMatching(Argument::cetera())->willReturn($expected); $repo->expects($this->once())->method('findOneMatching')->willReturn($expected);
$getRepo = $this->em->getRepository(ShortUrl::class)->willReturn($repo->reveal()); $this->em->expects($this->once())->method('getRepository')->with(ShortUrl::class)->willReturn($repo);
$this->titleResolutionHelper->expects($this->never())->method('processTitleAndValidateUrl');
$this->shortCodeHelper->method('ensureShortCodeUniqueness')->willReturn(true);
$result = $this->urlShortener->shorten($meta); $result = $this->urlShortener->shorten($meta);
$findExisting->shouldHaveBeenCalledOnce();
$getRepo->shouldHaveBeenCalledOnce();
$this->em->persist(Argument::cetera())->shouldNotHaveBeenCalled();
$this->titleResolutionHelper->processTitleAndValidateUrl(Argument::cetera())->shouldNotHaveBeenCalled();
self::assertSame($expected, $result); self::assertSame($expected, $result);
} }