'http', 'hostname' => 'foo.com', ]; private CommandTester $commandTester; private ObjectProphecy $urlShortener; public function setUp(): void { $this->urlShortener = $this->prophesize(UrlShortener::class); $command = new GenerateShortUrlCommand($this->urlShortener->reveal(), self::DOMAIN_CONFIG, 5); $app = new Application(); $app->add($command); $this->commandTester = new CommandTester($command); } /** @test */ public function properShortCodeIsCreatedIfLongUrlIsCorrect(): void { $shortUrl = new ShortUrl(''); $urlToShortCode = $this->urlShortener->urlToShortCode(Argument::cetera())->willReturn($shortUrl); $this->commandTester->execute([ 'longUrl' => 'http://domain.com/foo/bar', '--maxVisits' => '3', ]); $output = $this->commandTester->getDisplay(); self::assertEquals(ExitCodes::EXIT_SUCCESS, $this->commandTester->getStatusCode()); self::assertStringContainsString($shortUrl->toString(self::DOMAIN_CONFIG), $output); $urlToShortCode->shouldHaveBeenCalledOnce(); } /** @test */ public function exceptionWhileParsingLongUrlOutputsError(): void { $url = 'http://domain.com/invalid'; $this->urlShortener->urlToShortCode(Argument::cetera())->willThrow(InvalidUrlException::fromUrl($url)) ->shouldBeCalledOnce(); $this->commandTester->execute(['longUrl' => $url]); $output = $this->commandTester->getDisplay(); self::assertEquals(ExitCodes::EXIT_FAILURE, $this->commandTester->getStatusCode()); self::assertStringContainsString('Provided URL http://domain.com/invalid is invalid.', $output); } /** @test */ public function providingNonUniqueSlugOutputsError(): void { $urlToShortCode = $this->urlShortener->urlToShortCode(Argument::cetera())->willThrow( NonUniqueSlugException::fromSlug('my-slug'), ); $this->commandTester->execute(['longUrl' => 'http://domain.com/invalid', '--customSlug' => 'my-slug']); $output = $this->commandTester->getDisplay(); self::assertEquals(ExitCodes::EXIT_FAILURE, $this->commandTester->getStatusCode()); self::assertStringContainsString('Provided slug "my-slug" is already in use', $output); $urlToShortCode->shouldHaveBeenCalledOnce(); } /** @test */ public function properlyProcessesProvidedTags(): void { $shortUrl = new ShortUrl(''); $urlToShortCode = $this->urlShortener->urlToShortCode( Argument::type('string'), Argument::that(function (array $tags) { Assert::assertEquals(['foo', 'bar', 'baz', 'boo', 'zar'], $tags); return $tags; }), Argument::cetera(), )->willReturn($shortUrl); $this->commandTester->execute([ 'longUrl' => 'http://domain.com/foo/bar', '--tags' => ['foo,bar', 'baz', 'boo,zar,baz'], ]); $output = $this->commandTester->getDisplay(); self::assertEquals(ExitCodes::EXIT_SUCCESS, $this->commandTester->getStatusCode()); self::assertStringContainsString($shortUrl->toString(self::DOMAIN_CONFIG), $output); $urlToShortCode->shouldHaveBeenCalledOnce(); } /** * @test * @dataProvider provideFlags */ public function urlValidationHasExpectedValueBasedOnProvidedTags(array $options, ?bool $expectedValidateUrl): void { $shortUrl = new ShortUrl(''); $urlToShortCode = $this->urlShortener->urlToShortCode( Argument::type('string'), Argument::type('array'), Argument::that(function (ShortUrlMeta $meta) use ($expectedValidateUrl) { Assert::assertEquals($expectedValidateUrl, $meta->doValidateUrl()); return $meta; }), )->willReturn($shortUrl); $options['longUrl'] = 'http://domain.com/foo/bar'; $this->commandTester->execute($options); $urlToShortCode->shouldHaveBeenCalledOnce(); } public function provideFlags(): iterable { yield 'no flags' => [[], null]; yield 'no-validate-url only' => [['--no-validate-url' => true], false]; yield 'validate-url' => [['--validate-url' => true], true]; yield 'both flags' => [['--validate-url' => true, '--no-validate-url' => true], false]; } }