diff --git a/module/Core/src/Exception/ShortCodeCannotBeRegeneratedException.php b/module/Core/src/Exception/ShortCodeCannotBeRegeneratedException.php index e1df3068..fad5805d 100644 --- a/module/Core/src/Exception/ShortCodeCannotBeRegeneratedException.php +++ b/module/Core/src/Exception/ShortCodeCannotBeRegeneratedException.php @@ -6,24 +6,13 @@ namespace Shlinkio\Shlink\Core\Exception; class ShortCodeCannotBeRegeneratedException extends RuntimeException { - /** @var @bool */ - private $reasonIsSlug = false; - public static function forShortUrlWithCustomSlug(): self { - $e = new self('The short code cannot be regenerated on ShortUrls where a custom slug was provided.'); - $e->reasonIsSlug = true; - - return $e; + return new self('The short code cannot be regenerated on ShortUrls where a custom slug was provided.'); } public static function forShortUrlAlreadyPersisted(): self { return new self('The short code can be regenerated only on new ShortUrls which have not been persisted yet.'); } - - public function reasonIsSlug(): bool - { - return $this->reasonIsSlug; - } } diff --git a/module/Core/test/Entity/ShortUrlTest.php b/module/Core/test/Entity/ShortUrlTest.php new file mode 100644 index 00000000..98404ca1 --- /dev/null +++ b/module/Core/test/Entity/ShortUrlTest.php @@ -0,0 +1,51 @@ +expectException(ShortCodeCannotBeRegeneratedException::class); + $this->expectExceptionMessage($expectedMessage); + + $shortUrl->regenerateShortCode(); + } + + public function provideInvalidShortUrls(): iterable + { + yield 'with custom slug' => [ + new ShortUrl('', ShortUrlMeta::createFromRawData(['customSlug' => 'custom-slug'])), + 'The short code cannot be regenerated on ShortUrls where a custom slug was provided.', + ]; + yield 'already persisted' => [ + (new ShortUrl(''))->setId('1'), + 'The short code can be regenerated only on new ShortUrls which have not been persisted yet.', + ]; + } + + /** @test */ + public function regenerateShortCodeProperlyChangesTheValueOnValidShortUrls(): void + { + $shortUrl = new ShortUrl(''); + $firstShortCode = $shortUrl->getShortCode(); + + $shortUrl->regenerateShortCode(); + $secondShortCode = $shortUrl->getShortCode(); + + $this->assertNotEquals($firstShortCode, $secondShortCode); + } +} diff --git a/module/Core/test/Service/UrlShortenerTest.php b/module/Core/test/Service/UrlShortenerTest.php index 0185ef1a..78e61a6a 100644 --- a/module/Core/test/Service/UrlShortenerTest.php +++ b/module/Core/test/Service/UrlShortenerTest.php @@ -81,6 +81,32 @@ class UrlShortenerTest extends TestCase $this->assertEquals('http://foobar.com/12345/hello?foo=bar', $shortUrl->getLongUrl()); } + /** @test */ + public function shortCodeIsRegeneratedIfAlreadyInUse(): void + { + $callIndex = 0; + $expectedCalls = 3; + $repo = $this->prophesize(ShortUrlRepository::class); + $shortCodeIsInUse = $repo->shortCodeIsInUse(Argument::cetera())->will( + function () use (&$callIndex, $expectedCalls) { + $callIndex++; + return $callIndex < $expectedCalls; + } + ); + $repo->findBy(Argument::cetera())->willReturn([]); + $getRepo = $this->em->getRepository(ShortUrl::class)->willReturn($repo->reveal()); + + $shortUrl = $this->urlShortener->urlToShortCode( + new Uri('http://foobar.com/12345/hello?foo=bar'), + [], + ShortUrlMeta::createEmpty() + ); + + $this->assertEquals('http://foobar.com/12345/hello?foo=bar', $shortUrl->getLongUrl()); + $getRepo->shouldBeCalledTimes($expectedCalls); + $shortCodeIsInUse->shouldBeCalledTimes($expectedCalls); + } + /** @test */ public function transactionIsRolledBackAndExceptionRethrownWhenExceptionIsThrown(): void { @@ -190,6 +216,12 @@ class UrlShortenerTest extends TestCase ShortUrlMeta::createFromRawData(['findIfExists' => true, 'validUntil' => Chronos::parse('2017-01-01')]), new ShortUrl($url, ShortUrlMeta::createFromRawData(['validUntil' => Chronos::parse('2017-01-01')])), ]; + yield [ + $url, + [], + ShortUrlMeta::createFromRawData(['findIfExists' => true, 'domain' => 'example.com']), + new ShortUrl($url, ShortUrlMeta::createFromRawData(['domain' => 'example.com'])), + ]; yield [ $url, ['baz', 'foo', 'bar'],