2023-03-09 16:56:54 +00:00
|
|
|
<?php declare(strict_types=1);
|
|
|
|
|
|
|
|
use Lewisdale\Webmentions\Endpoint;
|
2023-03-14 08:27:46 +00:00
|
|
|
use Lewisdale\Webmentions\Exceptions\InvalidTargetException;
|
|
|
|
use Lewisdale\Webmentions\Exceptions\InvalidUrlException;
|
|
|
|
use Lewisdale\Webmentions\Exceptions\SourceNotFoundException;
|
|
|
|
use Lewisdale\Webmentions\Exceptions\TargetNotMentionedException;
|
2023-03-14 09:12:53 +00:00
|
|
|
use Lewisdale\Webmentions\Gateways\WebmentionGatewayInterface;
|
|
|
|
use Lewisdale\Webmentions\Models\MentionType;
|
|
|
|
use Lewisdale\Webmentions\Models\Webmention;
|
2023-03-09 16:56:54 +00:00
|
|
|
use PHPUnit\Framework\TestCase;
|
|
|
|
use PHPUnit\Framework\Attributes\TestWith;
|
2023-03-14 08:27:46 +00:00
|
|
|
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
|
|
|
use Symfony\Contracts\HttpClient\ResponseInterface;
|
2023-03-09 16:56:54 +00:00
|
|
|
|
|
|
|
class EndpointTest extends TestCase {
|
2023-03-14 13:54:05 +00:00
|
|
|
private function objectContains(string $key, mixed $value) {
|
|
|
|
return $this->callback(fn(object $obj) => $obj->$key === $value);
|
|
|
|
}
|
|
|
|
|
2023-03-09 16:56:54 +00:00
|
|
|
#[TestWith(["https://my.url.com", true])]
|
|
|
|
#[TestWith(["my.url.com", false])]
|
|
|
|
public function testValidatesUrls(string $url, bool $expected)
|
|
|
|
{
|
2023-03-14 09:12:53 +00:00
|
|
|
$endpoint = new Endpoint($this->createMock(HttpClientInterface::class), $this->createMock(WebmentionGatewayInterface::class));
|
2023-03-09 16:56:54 +00:00
|
|
|
$this->assertEquals($expected, $endpoint->validateUrl($url), "Expected $url");
|
|
|
|
}
|
2023-03-14 08:27:46 +00:00
|
|
|
|
|
|
|
#[TestWith(["https://my-valid-source.url", "htt://my-invalid-target.com"])]
|
|
|
|
#[TestWith(["my-invalid-source", "https://my-valid-target.com"])]
|
|
|
|
#[TestWith(["http:///an-invalid-source", "an-invalid-target"])]
|
|
|
|
public function testThrowsInvalidUrlExceptionIfTheUrlIsInvalid(string $source, string $target)
|
|
|
|
{
|
|
|
|
$this->expectException(InvalidUrlException::class);
|
2023-03-14 09:12:53 +00:00
|
|
|
$endpoint = new Endpoint($this->createMock(HttpClientInterface::class), $this->createMock(WebmentionGatewayInterface::class));
|
2023-03-14 08:27:46 +00:00
|
|
|
$endpoint->receiveWebmention($source, $target);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function testThrowsInvalidTargetExceptionIfTheTargetUrlIsNotOnCurrentSite()
|
|
|
|
{
|
|
|
|
$this->expectException(InvalidTargetException::class);
|
2023-03-14 09:12:53 +00:00
|
|
|
$endpoint = new Endpoint($this->createMock(HttpClientInterface::class), $this->createMock(WebmentionGatewayInterface::class));
|
2023-03-14 08:27:46 +00:00
|
|
|
$endpoint->receiveWebmention("https://a-valid-source.url", "https://not-my-site.com");
|
|
|
|
}
|
|
|
|
|
|
|
|
#[TestWith([404])]
|
|
|
|
#[TestWith([401])]
|
|
|
|
#[TestWith([500])]
|
|
|
|
#[TestWith([501])]
|
|
|
|
#[TestWith([502])]
|
|
|
|
#[TestWith([503])]
|
|
|
|
#[TestWith([500])]
|
|
|
|
public function testItShouldThrowASourceNotFoundExceptionIfTheSourceUrlIsUnreachable(int $statusCode)
|
|
|
|
{
|
|
|
|
$source = "https://my-valid-source-url.com";
|
|
|
|
$target = "https://lewisdale.dev/post/a-post-page";
|
|
|
|
|
|
|
|
$mockClient = $this->createMock(HttpClientInterface::class);
|
|
|
|
$mockResponse = $this->createMock(ResponseInterface::class);
|
|
|
|
|
|
|
|
$mockClient->expects($this->once())
|
|
|
|
->method('request')
|
|
|
|
->with($this->identicalTo('GET'), $this->identicalTo($source))
|
|
|
|
->will($this->returnValue($mockResponse));
|
|
|
|
|
|
|
|
$mockResponse->method('getStatusCode')
|
|
|
|
->will($this->returnValue($statusCode));
|
|
|
|
|
|
|
|
$this->expectException(SourceNotFoundException::class);
|
|
|
|
|
2023-03-14 09:12:53 +00:00
|
|
|
$endpoint = new Endpoint($mockClient, $this->createMock(WebmentionGatewayInterface::class));
|
2023-03-14 08:27:46 +00:00
|
|
|
$endpoint->receiveWebmention($source, $target);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function testItShouldThrowATargetNotMentionedErrorIfTheSourceDoesNotMentionTheTarget()
|
|
|
|
{
|
|
|
|
$source = "https://my-valid-source-url.com";
|
|
|
|
$target = "https://lewisdale.dev/post/a-post-page";
|
|
|
|
|
|
|
|
$content = <<<XML
|
|
|
|
<html>
|
|
|
|
<head>
|
|
|
|
</head>
|
|
|
|
<body>
|
|
|
|
<h1>Some content</h1>
|
|
|
|
<p>Here's some body content. It <a href="/another/page">contains a url</a>.</p>
|
|
|
|
<p>But it does not mention the target.</p>
|
|
|
|
</body>
|
|
|
|
</html>
|
|
|
|
XML;
|
|
|
|
|
|
|
|
$mockClient = $this->createMock(HttpClientInterface::class);
|
|
|
|
$mockResponse = $this->createMock(ResponseInterface::class);
|
|
|
|
|
|
|
|
$mockClient->expects($this->once())
|
|
|
|
->method('request')
|
|
|
|
->with($this->identicalTo('GET'), $this->identicalTo($source))
|
|
|
|
->will($this->returnValue($mockResponse));
|
|
|
|
|
|
|
|
$mockResponse->method('getStatusCode')
|
|
|
|
->will($this->returnValue(200));
|
|
|
|
|
|
|
|
$mockResponse->method('getContent')
|
|
|
|
->willReturn($content);
|
|
|
|
|
|
|
|
$this->expectException(TargetNotMentionedException::class);
|
|
|
|
|
2023-03-14 09:12:53 +00:00
|
|
|
$endpoint = new Endpoint($mockClient, $this->createMock(WebmentionGatewayInterface::class));
|
|
|
|
$endpoint->receiveWebmention($source, $target);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function testItShouldParseAWebmentionAsALikeIfItHasTheCorrectMicroFormat()
|
|
|
|
{
|
|
|
|
$source = "https://my-valid-source-url.com";
|
|
|
|
$target = "https://lewisdale.dev/post/a-post-page";
|
|
|
|
|
|
|
|
$content = <<<XML
|
|
|
|
<html>
|
|
|
|
<head>
|
|
|
|
</head>
|
|
|
|
<body>
|
2023-03-14 21:08:33 +00:00
|
|
|
<article>
|
|
|
|
<h1>Some content</h1>
|
|
|
|
<p>Here's some body content. It <a href="/another/page">contains a url</a>.</p>
|
|
|
|
<p>I'm liking <a href="$target" class="u-like-of">this post</a>.</p>
|
|
|
|
</article>
|
2023-03-14 09:12:53 +00:00
|
|
|
</body>
|
|
|
|
</html>
|
|
|
|
XML;
|
|
|
|
|
|
|
|
$mockClient = $this->createMock(HttpClientInterface::class);
|
|
|
|
$mockResponse = $this->createMock(ResponseInterface::class);
|
|
|
|
$mockGateway = $this->createMock(WebmentionGatewayInterface::class);
|
|
|
|
|
|
|
|
$mockClient->expects($this->once())
|
|
|
|
->method('request')
|
|
|
|
->with($this->identicalTo('GET'), $this->identicalTo($source))
|
|
|
|
->will($this->returnValue($mockResponse));
|
|
|
|
|
|
|
|
$mockResponse->method('getStatusCode')
|
|
|
|
->will($this->returnValue(200));
|
|
|
|
|
|
|
|
$mockResponse->method('getContent')
|
|
|
|
->willReturn($content);
|
|
|
|
|
|
|
|
$mockGateway->expects($this->once())
|
|
|
|
->method('save')
|
2023-03-14 13:54:05 +00:00
|
|
|
->with($this->objectContains('type', MentionType::Like));
|
2023-03-14 09:12:53 +00:00
|
|
|
|
|
|
|
$endpoint = new Endpoint($mockClient, $mockGateway);
|
|
|
|
|
|
|
|
$endpoint->receiveWebmention($source, $target);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function testItShouldParseAWebmentionAsAMentionIfItHasNoMicroformat()
|
|
|
|
{
|
|
|
|
$source = "https://my-valid-source-url.com";
|
|
|
|
$target = "https://lewisdale.dev/post/a-post-page";
|
|
|
|
|
|
|
|
$content = <<<XML
|
|
|
|
<html>
|
|
|
|
<head>
|
|
|
|
</head>
|
|
|
|
<body>
|
2023-03-14 21:08:33 +00:00
|
|
|
<article class="h-entry">
|
|
|
|
<h1>Some content</h1>
|
|
|
|
<p>Here's some body content. It <a href="/another/page">contains a url</a>.</p>
|
|
|
|
<p>I'm writing about <a href="$target" class="my-link">this post</a>.</p>
|
|
|
|
</article>
|
2023-03-14 09:12:53 +00:00
|
|
|
</body>
|
|
|
|
</html>
|
|
|
|
XML;
|
|
|
|
|
|
|
|
$mockClient = $this->createMock(HttpClientInterface::class);
|
|
|
|
$mockResponse = $this->createMock(ResponseInterface::class);
|
|
|
|
$mockGateway = $this->createMock(WebmentionGatewayInterface::class);
|
|
|
|
|
|
|
|
$mockClient->expects($this->once())
|
|
|
|
->method('request')
|
|
|
|
->with($this->identicalTo('GET'), $this->identicalTo($source))
|
|
|
|
->will($this->returnValue($mockResponse));
|
|
|
|
|
|
|
|
$mockResponse->method('getStatusCode')
|
|
|
|
->will($this->returnValue(200));
|
|
|
|
|
|
|
|
$mockResponse->method('getContent')
|
|
|
|
->willReturn($content);
|
|
|
|
|
|
|
|
$mockGateway->expects($this->once())
|
|
|
|
->method('save')
|
2023-03-14 13:54:05 +00:00
|
|
|
->with($this->objectContains('type', MentionType::Mention));
|
2023-03-14 09:12:53 +00:00
|
|
|
|
|
|
|
$endpoint = new Endpoint($mockClient, $mockGateway);
|
|
|
|
$endpoint->receiveWebmention($source, $target);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function testItShouldParseAWebmentionAsAReplyIfItHasTheCorrectMicroFormat()
|
|
|
|
{
|
|
|
|
$source = "https://my-valid-source-url.com";
|
|
|
|
$target = "https://lewisdale.dev/post/a-post-page";
|
|
|
|
|
|
|
|
$content = <<<XML
|
|
|
|
<html>
|
|
|
|
<head>
|
|
|
|
</head>
|
|
|
|
<body>
|
2023-03-14 21:08:33 +00:00
|
|
|
<article class="h-entry">
|
|
|
|
<h1>Some content</h1>
|
|
|
|
<p>Here's some body content. It <a href="/another/page">contains a url</a>.</p>
|
|
|
|
<p>I'm writing about <a href="$target" class="u-in-reply-to">this post</a>.</p>
|
|
|
|
</article>
|
2023-03-14 09:12:53 +00:00
|
|
|
</body>
|
|
|
|
</html>
|
|
|
|
XML;
|
|
|
|
|
|
|
|
$mockClient = $this->createMock(HttpClientInterface::class);
|
|
|
|
$mockResponse = $this->createMock(ResponseInterface::class);
|
|
|
|
$mockGateway = $this->createMock(WebmentionGatewayInterface::class);
|
|
|
|
|
|
|
|
$mockClient->expects($this->once())
|
|
|
|
->method('request')
|
|
|
|
->with($this->identicalTo('GET'), $this->identicalTo($source))
|
|
|
|
->will($this->returnValue($mockResponse));
|
|
|
|
|
|
|
|
$mockResponse->method('getStatusCode')
|
|
|
|
->will($this->returnValue(200));
|
|
|
|
|
|
|
|
$mockResponse->method('getContent')
|
|
|
|
->willReturn($content);
|
|
|
|
|
|
|
|
$mockGateway->expects($this->once())
|
|
|
|
->method('save')
|
2023-03-14 13:54:05 +00:00
|
|
|
->with($this->objectContains('type', MentionType::Reply));
|
|
|
|
|
|
|
|
$endpoint = new Endpoint($mockClient, $mockGateway);
|
|
|
|
$endpoint->receiveWebmention($source, $target);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function testItShouldParseAWebmentionAsARepost()
|
|
|
|
{
|
|
|
|
$source = "https://my-valid-source-url.com";
|
|
|
|
$target = "https://lewisdale.dev/post/a-post-page";
|
|
|
|
|
|
|
|
$content = <<<XML
|
|
|
|
<html>
|
|
|
|
<head>
|
|
|
|
</head>
|
|
|
|
<body>
|
2023-03-14 21:08:33 +00:00
|
|
|
<article="h-entry">
|
|
|
|
<h1>Some content</h1>
|
|
|
|
<p>Here's some body content. It <a href="/another/page">contains a url</a>.</p>
|
|
|
|
<p>I'm writing about <a href="$target" class="u-repost-of">this post</a>.</p>
|
|
|
|
</article>
|
2023-03-14 13:54:05 +00:00
|
|
|
</body>
|
|
|
|
</html>
|
|
|
|
XML;
|
|
|
|
|
|
|
|
$mockClient = $this->createMock(HttpClientInterface::class);
|
|
|
|
$mockResponse = $this->createMock(ResponseInterface::class);
|
|
|
|
$mockGateway = $this->createMock(WebmentionGatewayInterface::class);
|
2023-03-14 09:12:53 +00:00
|
|
|
|
2023-03-14 13:54:05 +00:00
|
|
|
$mockClient->expects($this->once())
|
|
|
|
->method('request')
|
|
|
|
->with($this->identicalTo('GET'), $this->identicalTo($source))
|
|
|
|
->will($this->returnValue($mockResponse));
|
|
|
|
|
|
|
|
$mockResponse->method('getStatusCode')
|
|
|
|
->will($this->returnValue(200));
|
|
|
|
|
|
|
|
$mockResponse->method('getContent')
|
|
|
|
->willReturn($content);
|
|
|
|
|
|
|
|
$mockGateway->expects($this->once())
|
|
|
|
->method('save')
|
|
|
|
->with($this->objectContains('type', MentionType::Repost));
|
2023-03-14 21:08:33 +00:00
|
|
|
|
2023-03-14 09:12:53 +00:00
|
|
|
$endpoint = new Endpoint($mockClient, $mockGateway);
|
2023-03-14 08:27:46 +00:00
|
|
|
$endpoint->receiveWebmention($source, $target);
|
|
|
|
}
|
2023-03-09 16:56:54 +00:00
|
|
|
}
|
|
|
|
?>
|