httpClient = $this->prophesize(ClientInterface::class); } /** @test */ public function exceptionIsThrownWhenUrlIsInvalid(): void { $request = $this->httpClient->request(Argument::cetera())->willThrow(ClientException::class); $request->shouldBeCalledOnce(); $this->expectException(InvalidUrlException::class); $this->urlValidator()->validateUrl('http://foobar.com/12345/hello?foo=bar', true); } /** @test */ public function expectedUrlIsCalledWhenTryingToVerify(): void { $expectedUrl = 'http://foobar.com'; $request = $this->httpClient->request( RequestMethodInterface::METHOD_GET, $expectedUrl, Argument::that(function (array $options) { Assert::assertArrayHasKey(RequestOptions::ALLOW_REDIRECTS, $options); Assert::assertEquals(['max' => 15], $options[RequestOptions::ALLOW_REDIRECTS]); Assert::assertArrayHasKey(RequestOptions::IDN_CONVERSION, $options); Assert::assertTrue($options[RequestOptions::IDN_CONVERSION]); Assert::assertArrayHasKey(RequestOptions::HEADERS, $options); Assert::assertArrayHasKey('User-Agent', $options[RequestOptions::HEADERS]); return true; }), )->willReturn(new Response()); $this->urlValidator()->validateUrl($expectedUrl, true); $request->shouldHaveBeenCalledOnce(); } /** @test */ public function noCheckIsPerformedWhenUrlValidationIsDisabled(): void { $request = $this->httpClient->request(Argument::cetera())->willReturn(new Response()); $this->urlValidator()->validateUrl('', false); $request->shouldNotHaveBeenCalled(); } /** @test */ public function validateUrlWithTitleReturnsNullWhenRequestFailsAndValidationIsDisabled(): void { $request = $this->httpClient->request(Argument::cetera())->willThrow(ClientException::class); $result = $this->urlValidator(true)->validateUrlWithTitle('http://foobar.com/12345/hello?foo=bar', false); self::assertNull($result); $request->shouldHaveBeenCalledOnce(); } /** @test */ public function validateUrlWithTitleReturnsNullWhenAutoResolutionIsDisabled(): void { $request = $this->httpClient->request(Argument::cetera())->willReturn($this->respWithTitle()); $result = $this->urlValidator()->validateUrlWithTitle('http://foobar.com/12345/hello?foo=bar', false); self::assertNull($result); $request->shouldNotHaveBeenCalled(); } /** @test */ public function validateUrlWithTitleReturnsNullWhenAutoResolutionIsDisabledAndValidationIsEnabled(): void { $request = $this->httpClient->request(RequestMethodInterface::METHOD_HEAD, Argument::cetera())->willReturn( $this->respWithTitle(), ); $result = $this->urlValidator()->validateUrlWithTitle('http://foobar.com/12345/hello?foo=bar', true); self::assertNull($result); $request->shouldHaveBeenCalledOnce(); } /** @test */ public function validateUrlWithTitleResolvesTitleWhenAutoResolutionIsEnabled(): void { $request = $this->httpClient->request(RequestMethodInterface::METHOD_GET, Argument::cetera())->willReturn( $this->respWithTitle(), ); $result = $this->urlValidator(true)->validateUrlWithTitle('http://foobar.com/12345/hello?foo=bar', true); self::assertEquals('Resolved "title"', $result); $request->shouldHaveBeenCalledOnce(); } /** @test */ public function validateUrlWithTitleReturnsNullWhenAutoResolutionIsEnabledAndReturnedContentTypeIsInvalid(): void { $request = $this->httpClient->request(RequestMethodInterface::METHOD_GET, Argument::cetera())->willReturn( new Response('php://memory', 200, ['Content-Type' => 'application/octet-stream']), ); $result = $this->urlValidator(true)->validateUrlWithTitle('http://foobar.com/12345/hello?foo=bar', true); self::assertNull($result); $request->shouldHaveBeenCalledOnce(); } /** @test */ public function validateUrlWithTitleReturnsNullWhenAutoResolutionIsEnabledAndBodyDoesNotContainTitle(): void { $request = $this->httpClient->request(RequestMethodInterface::METHOD_GET, Argument::cetera())->willReturn( new Response($this->createStreamWithContent('No title'), 200, ['Content-Type' => 'text/html']), ); $result = $this->urlValidator(true)->validateUrlWithTitle('http://foobar.com/12345/hello?foo=bar', true); self::assertNull($result); $request->shouldHaveBeenCalledOnce(); } private function respWithTitle(): Response { $body = $this->createStreamWithContent(' Resolved "title" '); return new Response($body, 200, ['Content-Type' => 'TEXT/html; charset=utf-8']); } private function createStreamWithContent(string $content): Stream { $body = new Stream('php://temp', 'wr'); $body->write($content); $body->rewind(); return $body; } public function urlValidator(bool $autoResolveTitles = false): UrlValidator { return new UrlValidator( $this->httpClient->reveal(), new UrlShortenerOptions(autoResolveTitles: $autoResolveTitles), ); } }