mirror of
https://github.com/shlinkio/shlink.git
synced 2024-11-22 08:56:42 -06:00
Migrated ImportedLinksProcessorTest to use PHPUnit mocks
This commit is contained in:
parent
10b0ec301b
commit
173420c608
@ -7,10 +7,8 @@ namespace ShlinkioTest\Shlink\Core\Importer;
|
|||||||
use Cake\Chronos\Chronos;
|
use Cake\Chronos\Chronos;
|
||||||
use Doctrine\Common\Collections\ArrayCollection;
|
use Doctrine\Common\Collections\ArrayCollection;
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
use PHPUnit\Framework\MockObject\MockObject;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
use Prophecy\Argument;
|
|
||||||
use Prophecy\PhpUnit\ProphecyTrait;
|
|
||||||
use Prophecy\Prophecy\ObjectProphecy;
|
|
||||||
use RuntimeException;
|
use RuntimeException;
|
||||||
use Shlinkio\Shlink\Core\Importer\ImportedLinksProcessor;
|
use Shlinkio\Shlink\Core\Importer\ImportedLinksProcessor;
|
||||||
use Shlinkio\Shlink\Core\ShortUrl\Entity\ShortUrl;
|
use Shlinkio\Shlink\Core\ShortUrl\Entity\ShortUrl;
|
||||||
@ -23,6 +21,7 @@ use Shlinkio\Shlink\Importer\Model\ImportedShlinkUrl;
|
|||||||
use Shlinkio\Shlink\Importer\Model\ImportedShlinkVisit;
|
use Shlinkio\Shlink\Importer\Model\ImportedShlinkVisit;
|
||||||
use Shlinkio\Shlink\Importer\Params\ImportParams;
|
use Shlinkio\Shlink\Importer\Params\ImportParams;
|
||||||
use Shlinkio\Shlink\Importer\Sources\ImportSource;
|
use Shlinkio\Shlink\Importer\Sources\ImportSource;
|
||||||
|
use stdClass;
|
||||||
use Symfony\Component\Console\Style\StyleInterface;
|
use Symfony\Component\Console\Style\StyleInterface;
|
||||||
|
|
||||||
use function count;
|
use function count;
|
||||||
@ -32,32 +31,30 @@ use function str_contains;
|
|||||||
|
|
||||||
class ImportedLinksProcessorTest extends TestCase
|
class ImportedLinksProcessorTest extends TestCase
|
||||||
{
|
{
|
||||||
use ProphecyTrait;
|
|
||||||
|
|
||||||
private ImportedLinksProcessor $processor;
|
private ImportedLinksProcessor $processor;
|
||||||
private ObjectProphecy $em;
|
private MockObject $em;
|
||||||
private ObjectProphecy $shortCodeHelper;
|
private MockObject $shortCodeHelper;
|
||||||
private ObjectProphecy $repo;
|
private MockObject $repo;
|
||||||
private ObjectProphecy $io;
|
private MockObject $io;
|
||||||
|
|
||||||
protected function setUp(): void
|
protected function setUp(): void
|
||||||
{
|
{
|
||||||
$this->em = $this->prophesize(EntityManagerInterface::class);
|
$this->em = $this->createMock(EntityManagerInterface::class);
|
||||||
$this->repo = $this->prophesize(ShortUrlRepositoryInterface::class);
|
$this->repo = $this->createMock(ShortUrlRepositoryInterface::class);
|
||||||
$this->em->getRepository(ShortUrl::class)->willReturn($this->repo->reveal());
|
$this->em->method('getRepository')->with($this->equalTo(ShortUrl::class))->willReturn($this->repo);
|
||||||
|
|
||||||
$this->shortCodeHelper = $this->prophesize(ShortCodeUniquenessHelperInterface::class);
|
$this->shortCodeHelper = $this->createMock(ShortCodeUniquenessHelperInterface::class);
|
||||||
$batchHelper = $this->prophesize(DoctrineBatchHelperInterface::class);
|
$batchHelper = $this->createMock(DoctrineBatchHelperInterface::class);
|
||||||
$batchHelper->wrapIterable(Argument::cetera())->willReturnArgument(0);
|
$batchHelper->method('wrapIterable')->willReturnArgument(0);
|
||||||
|
|
||||||
$this->processor = new ImportedLinksProcessor(
|
$this->processor = new ImportedLinksProcessor(
|
||||||
$this->em->reveal(),
|
$this->em,
|
||||||
new SimpleShortUrlRelationResolver(),
|
new SimpleShortUrlRelationResolver(),
|
||||||
$this->shortCodeHelper->reveal(),
|
$this->shortCodeHelper,
|
||||||
$batchHelper->reveal(),
|
$batchHelper,
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->io = $this->prophesize(StyleInterface::class);
|
$this->io = $this->createMock(StyleInterface::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @test */
|
/** @test */
|
||||||
@ -70,16 +67,16 @@ class ImportedLinksProcessorTest extends TestCase
|
|||||||
];
|
];
|
||||||
$expectedCalls = count($urls);
|
$expectedCalls = count($urls);
|
||||||
|
|
||||||
$importedUrlExists = $this->repo->findOneByImportedUrl(Argument::cetera())->willReturn(null);
|
$this->repo->expects($this->exactly($expectedCalls))->method('findOneByImportedUrl')->willReturn(null);
|
||||||
$ensureUniqueness = $this->shortCodeHelper->ensureShortCodeUniqueness(Argument::cetera())->willReturn(true);
|
$this->shortCodeHelper->expects($this->exactly($expectedCalls))
|
||||||
$persist = $this->em->persist(Argument::type(ShortUrl::class));
|
->method('ensureShortCodeUniqueness')
|
||||||
|
->willReturn(true);
|
||||||
|
$this->em->expects($this->exactly($expectedCalls))->method('persist')->with(
|
||||||
|
$this->isInstanceOf(ShortUrl::class),
|
||||||
|
);
|
||||||
|
$this->io->expects($this->exactly($expectedCalls))->method('text')->with($this->isType('string'));
|
||||||
|
|
||||||
$this->processor->process($this->io->reveal(), $urls, $this->buildParams());
|
$this->processor->process($this->io, $urls, $this->buildParams());
|
||||||
|
|
||||||
$importedUrlExists->shouldHaveBeenCalledTimes($expectedCalls);
|
|
||||||
$ensureUniqueness->shouldHaveBeenCalledTimes($expectedCalls);
|
|
||||||
$persist->shouldHaveBeenCalledTimes($expectedCalls);
|
|
||||||
$this->io->text(Argument::type('string'))->shouldHaveBeenCalledTimes($expectedCalls);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @test */
|
/** @test */
|
||||||
@ -91,26 +88,21 @@ class ImportedLinksProcessorTest extends TestCase
|
|||||||
new ImportedShlinkUrl(ImportSource::BITLY, 'baz', [], Chronos::now(), null, 'baz', null),
|
new ImportedShlinkUrl(ImportSource::BITLY, 'baz', [], Chronos::now(), null, 'baz', null),
|
||||||
];
|
];
|
||||||
|
|
||||||
$importedUrlExists = $this->repo->findOneByImportedUrl(Argument::cetera())->willReturn(null);
|
$this->repo->expects($this->exactly(3))->method('findOneByImportedUrl')->willReturn(null);
|
||||||
$ensureUniqueness = $this->shortCodeHelper->ensureShortCodeUniqueness(Argument::cetera())->willReturn(true);
|
$this->shortCodeHelper->expects($this->exactly(3))->method('ensureShortCodeUniqueness')->willReturn(true);
|
||||||
$persist = $this->em->persist(Argument::type(ShortUrl::class))->will(function (array $args): void {
|
$this->em->expects($this->exactly(3))->method('persist')->with(
|
||||||
/** @var ShortUrl $shortUrl */
|
$this->isInstanceOf(ShortUrl::class),
|
||||||
[$shortUrl] = $args;
|
)->willReturnCallback(function (ShortUrl $shortUrl): void {
|
||||||
|
|
||||||
if ($shortUrl->getShortCode() === 'baz') {
|
if ($shortUrl->getShortCode() === 'baz') {
|
||||||
throw new RuntimeException('Whatever error');
|
throw new RuntimeException('Whatever error');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
$textCalls = $this->setUpIoText('<comment>Skipped</comment>. Reason: Whatever error', '<info>Imported</info>');
|
||||||
|
|
||||||
$this->processor->process($this->io->reveal(), $urls, $this->buildParams());
|
$this->processor->process($this->io, $urls, $this->buildParams());
|
||||||
|
|
||||||
$importedUrlExists->shouldHaveBeenCalledTimes(3);
|
self::assertEquals(2, $textCalls->importedCount);
|
||||||
$ensureUniqueness->shouldHaveBeenCalledTimes(3);
|
self::assertEquals(1, $textCalls->skippedCount);
|
||||||
$persist->shouldHaveBeenCalledTimes(3);
|
|
||||||
$this->io->text(Argument::containingString('<info>Imported</info>'))->shouldHaveBeenCalledTimes(2);
|
|
||||||
$this->io->text(
|
|
||||||
Argument::containingString('<comment>Skipped</comment>. Reason: Whatever error'),
|
|
||||||
)->shouldHaveBeenCalledOnce();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @test */
|
/** @test */
|
||||||
@ -124,24 +116,18 @@ class ImportedLinksProcessorTest extends TestCase
|
|||||||
new ImportedShlinkUrl(ImportSource::BITLY, 'baz3', [], Chronos::now(), null, 'baz3', null),
|
new ImportedShlinkUrl(ImportSource::BITLY, 'baz3', [], Chronos::now(), null, 'baz3', null),
|
||||||
];
|
];
|
||||||
|
|
||||||
$importedUrlExists = $this->repo->findOneByImportedUrl(Argument::cetera())->will(
|
$this->repo->expects($this->exactly(count($urls)))->method('findOneByImportedUrl')->willReturnCallback(
|
||||||
function (array $args): ?ShortUrl {
|
fn (ImportedShlinkUrl $url): ?ShortUrl
|
||||||
/** @var ImportedShlinkUrl $url */
|
=> contains(['foo', 'baz2', 'baz3'], $url->longUrl) ? ShortUrl::fromImport($url, true) : null,
|
||||||
[$url] = $args;
|
|
||||||
|
|
||||||
return contains(['foo', 'baz2', 'baz3'], $url->longUrl) ? ShortUrl::fromImport($url, true) : null;
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
$ensureUniqueness = $this->shortCodeHelper->ensureShortCodeUniqueness(Argument::cetera())->willReturn(true);
|
$this->shortCodeHelper->expects($this->exactly(2))->method('ensureShortCodeUniqueness')->willReturn(true);
|
||||||
$persist = $this->em->persist(Argument::type(ShortUrl::class));
|
$this->em->expects($this->exactly(2))->method('persist')->with($this->isInstanceOf(ShortUrl::class));
|
||||||
|
$textCalls = $this->setUpIoText();
|
||||||
|
|
||||||
$this->processor->process($this->io->reveal(), $urls, $this->buildParams());
|
$this->processor->process($this->io, $urls, $this->buildParams());
|
||||||
|
|
||||||
$importedUrlExists->shouldHaveBeenCalledTimes(count($urls));
|
self::assertEquals(2, $textCalls->importedCount);
|
||||||
$ensureUniqueness->shouldHaveBeenCalledTimes(2);
|
self::assertEquals(3, $textCalls->skippedCount);
|
||||||
$persist->shouldHaveBeenCalledTimes(2);
|
|
||||||
$this->io->text(Argument::containingString('Skipped'))->shouldHaveBeenCalledTimes(3);
|
|
||||||
$this->io->text(Argument::containingString('Imported'))->shouldHaveBeenCalledTimes(2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @test */
|
/** @test */
|
||||||
@ -155,32 +141,20 @@ class ImportedLinksProcessorTest extends TestCase
|
|||||||
new ImportedShlinkUrl(ImportSource::BITLY, 'baz3', [], Chronos::now(), null, 'baz3', 'bar'),
|
new ImportedShlinkUrl(ImportSource::BITLY, 'baz3', [], Chronos::now(), null, 'baz3', 'bar'),
|
||||||
];
|
];
|
||||||
|
|
||||||
$importedUrlExists = $this->repo->findOneByImportedUrl(Argument::cetera())->willReturn(null);
|
$this->repo->expects($this->exactly(count($urls)))->method('findOneByImportedUrl')->willReturn(null);
|
||||||
$failingEnsureUniqueness = $this->shortCodeHelper->ensureShortCodeUniqueness(
|
$this->shortCodeHelper->expects($this->exactly(7))->method('ensureShortCodeUniqueness')->willReturnCallback(
|
||||||
Argument::any(),
|
fn ($_, bool $hasCustomSlug) => ! $hasCustomSlug,
|
||||||
true,
|
);
|
||||||
)->willReturn(false);
|
$this->em->expects($this->exactly(2))->method('persist')->with($this->isInstanceOf(ShortUrl::class));
|
||||||
$successEnsureUniqueness = $this->shortCodeHelper->ensureShortCodeUniqueness(
|
$this->io->expects($this->exactly(5))->method('choice')->willReturnCallback(function (string $question) {
|
||||||
Argument::any(),
|
|
||||||
false,
|
|
||||||
)->willReturn(true);
|
|
||||||
$choice = $this->io->choice(Argument::cetera())->will(function (array $args) {
|
|
||||||
/** @var ImportedShlinkUrl $url */
|
|
||||||
[$question] = $args;
|
|
||||||
|
|
||||||
return some(['foo', 'baz2', 'baz3'], fn (string $item) => str_contains($question, $item)) ? 'Skip' : '';
|
return some(['foo', 'baz2', 'baz3'], fn (string $item) => str_contains($question, $item)) ? 'Skip' : '';
|
||||||
});
|
});
|
||||||
$persist = $this->em->persist(Argument::type(ShortUrl::class));
|
$textCalls = $this->setUpIoText('Error');
|
||||||
|
|
||||||
$this->processor->process($this->io->reveal(), $urls, $this->buildParams());
|
$this->processor->process($this->io, $urls, $this->buildParams());
|
||||||
|
|
||||||
$importedUrlExists->shouldHaveBeenCalledTimes(count($urls));
|
self::assertEquals(2, $textCalls->importedCount);
|
||||||
$failingEnsureUniqueness->shouldHaveBeenCalledTimes(5);
|
self::assertEquals(3, $textCalls->skippedCount);
|
||||||
$successEnsureUniqueness->shouldHaveBeenCalledTimes(2);
|
|
||||||
$choice->shouldHaveBeenCalledTimes(5);
|
|
||||||
$persist->shouldHaveBeenCalledTimes(2);
|
|
||||||
$this->io->text(Argument::containingString('Error'))->shouldHaveBeenCalledTimes(3);
|
|
||||||
$this->io->text(Argument::containingString('Imported'))->shouldHaveBeenCalledTimes(2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -193,18 +167,16 @@ class ImportedLinksProcessorTest extends TestCase
|
|||||||
int $amountOfPersistedVisits,
|
int $amountOfPersistedVisits,
|
||||||
?ShortUrl $foundShortUrl,
|
?ShortUrl $foundShortUrl,
|
||||||
): void {
|
): void {
|
||||||
$findExisting = $this->repo->findOneByImportedUrl(Argument::cetera())->willReturn($foundShortUrl);
|
$this->repo->expects($this->once())->method('findOneByImportedUrl')->willReturn($foundShortUrl);
|
||||||
$ensureUniqueness = $this->shortCodeHelper->ensureShortCodeUniqueness(Argument::cetera())->willReturn(true);
|
$this->shortCodeHelper->expects($this->exactly($foundShortUrl === null ? 1 : 0))
|
||||||
$persistUrl = $this->em->persist(Argument::type(ShortUrl::class));
|
->method('ensureShortCodeUniqueness')
|
||||||
$persistVisits = $this->em->persist(Argument::type(Visit::class));
|
->willReturn(true);
|
||||||
|
$this->em->expects($this->exactly($amountOfPersistedVisits + ($foundShortUrl === null ? 1 : 0)))->method(
|
||||||
|
'persist',
|
||||||
|
)->with($this->callback(fn (object $arg) => $arg instanceof ShortUrl || $arg instanceof Visit));
|
||||||
|
$this->io->expects($this->once())->method('text')->with($this->stringContains($expectedOutput));
|
||||||
|
|
||||||
$this->processor->process($this->io->reveal(), [$importedUrl], $this->buildParams());
|
$this->processor->process($this->io, [$importedUrl], $this->buildParams());
|
||||||
|
|
||||||
$findExisting->shouldHaveBeenCalledOnce();
|
|
||||||
$ensureUniqueness->shouldHaveBeenCalledTimes($foundShortUrl === null ? 1 : 0);
|
|
||||||
$persistUrl->shouldHaveBeenCalledTimes($foundShortUrl === null ? 1 : 0);
|
|
||||||
$persistVisits->shouldHaveBeenCalledTimes($amountOfPersistedVisits);
|
|
||||||
$this->io->text(Argument::containingString($expectedOutput))->shouldHaveBeenCalledOnce();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function provideUrlsWithVisits(): iterable
|
public function provideUrlsWithVisits(): iterable
|
||||||
@ -251,4 +223,23 @@ class ImportedLinksProcessorTest extends TestCase
|
|||||||
{
|
{
|
||||||
return ImportSource::BITLY->toParamsWithCallableMap(['import_short_codes' => static fn () => true]);
|
return ImportSource::BITLY->toParamsWithCallableMap(['import_short_codes' => static fn () => true]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function setUpIoText(string $skippedText = 'Skipped', string $importedText = 'Imported'): stdClass
|
||||||
|
{
|
||||||
|
$counts = new stdClass();
|
||||||
|
$counts->importedCount = 0;
|
||||||
|
$counts->skippedCount = 0;
|
||||||
|
|
||||||
|
$this->io->method('text')->willReturnCallback(
|
||||||
|
function (string $output) use ($counts, $skippedText, $importedText) {
|
||||||
|
if (str_contains($output, $skippedText)) {
|
||||||
|
$counts->skippedCount++;
|
||||||
|
} elseif (str_contains($output, $importedText)) {
|
||||||
|
$counts->importedCount++;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
return $counts;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user