urlShortener = $this->createMock(UrlShortenerInterface::class); $this->stringifier = $this->createMock(ShortUrlStringifierInterface::class); $command = new CreateShortUrlCommand( $this->urlShortener, $this->stringifier, new UrlShortenerOptions( domain: ['hostname' => self::DEFAULT_DOMAIN, 'schema' => ''], defaultShortCodesLength: 5, ), ); $this->commandTester = $this->testerForCommand($command); } /** @test */ public function properShortCodeIsCreatedIfLongUrlIsCorrect(): void { $shortUrl = ShortUrl::createEmpty(); $this->urlShortener->expects($this->once())->method('shorten')->withAnyParameters()->willReturn($shortUrl); $this->stringifier->expects($this->once())->method('stringify')->with($shortUrl)->willReturn( 'stringified_short_url', ); $this->commandTester->execute([ 'longUrl' => 'http://domain.com/foo/bar', '--max-visits' => '3', ]); $output = $this->commandTester->getDisplay(); self::assertEquals(ExitCodes::EXIT_SUCCESS, $this->commandTester->getStatusCode()); self::assertStringContainsString('stringified_short_url', $output); } /** @test */ public function exceptionWhileParsingLongUrlOutputsError(): void { $url = 'http://domain.com/invalid'; $this->urlShortener->expects($this->once())->method('shorten')->withAnyParameters()->willThrowException( InvalidUrlException::fromUrl($url), ); $this->stringifier->method('stringify')->with($this->isInstanceOf(ShortUrl::class))->willReturn(''); $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 { $this->urlShortener->expects($this->once())->method('shorten')->withAnyParameters()->willThrowException( NonUniqueSlugException::fromSlug('my-slug'), ); $this->stringifier->method('stringify')->with($this->isInstanceOf(ShortUrl::class))->willReturn(''); $this->commandTester->execute(['longUrl' => 'http://domain.com/invalid', '--custom-slug' => '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); } /** @test */ public function properlyProcessesProvidedTags(): void { $shortUrl = ShortUrl::createEmpty(); $this->urlShortener->expects($this->once())->method('shorten')->with( $this->callback(function (ShortUrlCreation $meta) { $tags = $meta->getTags(); Assert::assertEquals(['foo', 'bar', 'baz', 'boo', 'zar'], $tags); return true; }), )->willReturn($shortUrl); $this->stringifier->expects($this->once())->method('stringify')->with($shortUrl)->willReturn( 'stringified_short_url', ); $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('stringified_short_url', $output); } /** * @test * @dataProvider provideDomains */ public function properlyProcessesProvidedDomain(array $input, ?string $expectedDomain): void { $this->urlShortener->expects($this->once())->method('shorten')->with( $this->callback(function (ShortUrlCreation $meta) use ($expectedDomain) { Assert::assertEquals($expectedDomain, $meta->getDomain()); return true; }), )->willReturn(ShortUrl::createEmpty()); $this->stringifier->method('stringify')->with($this->isInstanceOf(ShortUrl::class))->willReturn(''); $input['longUrl'] = 'http://domain.com/foo/bar'; $this->commandTester->execute($input); self::assertEquals(ExitCodes::EXIT_SUCCESS, $this->commandTester->getStatusCode()); } public function provideDomains(): iterable { yield 'no domain' => [[], null]; yield 'non-default domain foo' => [['--domain' => 'foo.com'], 'foo.com']; yield 'non-default domain bar' => [['-d' => 'bar.com'], 'bar.com']; yield 'default domain' => [['--domain' => self::DEFAULT_DOMAIN], null]; } /** * @test * @dataProvider provideFlags */ public function urlValidationHasExpectedValueBasedOnProvidedFlags(array $options, ?bool $expectedValidateUrl): void { $shortUrl = ShortUrl::createEmpty(); $this->urlShortener->expects($this->once())->method('shorten')->with( $this->callback(function (ShortUrlCreation $meta) use ($expectedValidateUrl) { Assert::assertEquals($expectedValidateUrl, $meta->doValidateUrl()); return true; }), )->willReturn($shortUrl); $this->stringifier->method('stringify')->with($this->isInstanceOf(ShortUrl::class))->willReturn(''); $options['longUrl'] = 'http://domain.com/foo/bar'; $this->commandTester->execute($options); } public function provideFlags(): iterable { yield 'no flags' => [[], null]; yield 'validate-url' => [['--validate-url' => true], true]; } }