fix: full-form internal links follow the {{link:}} target rules (ruling P10)
One PostIdParser for {{link:}} and select_post; post_link_url_<type> needs a
living, readable, non-attachment target of exactly that type.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace LIT\MCP\Tests\Unit\Integrations\Divi\Compose;
|
||||
|
||||
use LIT\MCP\Integrations\Divi\Compose\PostIdParser;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
final class PostIdParserTest extends TestCase
|
||||
{
|
||||
public function testAcceptsPositiveIdsAsIntOrDigits(): void
|
||||
{
|
||||
self::assertSame(839, PostIdParser::parse(839));
|
||||
self::assertSame(839, PostIdParser::parse('839'));
|
||||
self::assertSame(PHP_INT_MAX, PostIdParser::parse((string) PHP_INT_MAX));
|
||||
}
|
||||
|
||||
/** Ruling P10: one rule for {{link:}} and post_link_url_* – no zero, sign, padding, slug or overflow. */
|
||||
public function testRefusesEverythingElse(): void
|
||||
{
|
||||
$bad = [
|
||||
0, -3, '0', '-3', '+3', '0839', '8 39', ' 839', '839 ', "839\n", '839.0', '0x1f', '1e3', 'impressum',
|
||||
'99999999999999999999', '9223372036854775808', 1.5, 839.0, null, [], true, false,
|
||||
];
|
||||
foreach ($bad as $value) {
|
||||
self::assertNull(PostIdParser::parse($value), var_export($value, true));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -415,6 +415,11 @@ final class StoredNodeGuardTest extends TestCase
|
||||
{
|
||||
return $this->inner->canReadPost($id);
|
||||
}
|
||||
|
||||
public function linkTargetType(int $id): ?string
|
||||
{
|
||||
return $this->inner->linkTargetType($id);
|
||||
}
|
||||
};
|
||||
$references = new VariableRef(
|
||||
DiviFixtures::designSystem(),
|
||||
|
||||
@@ -449,6 +449,64 @@ final class VariableRefTest extends TestCase
|
||||
}
|
||||
}
|
||||
|
||||
/** Ruling P10: a full-form internal link follows the {{link:}} target rules, its type included. */
|
||||
public function testFullFormInternalLinksFollowTheLinkTargetRules(): void
|
||||
{
|
||||
$ref = self::ref([
|
||||
'post_link_url_page' => ['post_id' => 'select_post'],
|
||||
'post_link_url_post' => ['post_id' => 'select_post'],
|
||||
]);
|
||||
$sanitizer = ComposeFixture::sanitizer();
|
||||
|
||||
self::assertSame(
|
||||
self::content('post_link_url_post', '{"post_id":"840"}'),
|
||||
$ref->canonical(self::content('post_link_url_post', '{"post_id":"840"}'), $sanitizer, true)
|
||||
);
|
||||
self::assertSame(
|
||||
self::content('post_link_url_post', '{"post_id":840}'),
|
||||
$ref->canonical(self::content('post_link_url_post', '{"post_id":840}'), $sanitizer, true)
|
||||
);
|
||||
$refused = [
|
||||
'a post is no page' => self::content('post_link_url_page', '{"post_id":"840"}'),
|
||||
'a post is no page (int)' => self::content('post_link_url_page', '{"post_id":840}'),
|
||||
'a page is no post' => self::content('post_link_url_post', '{"post_id":"12"}'),
|
||||
'no link target' => self::content('post_link_url_page', '{"post_id":"666"}'),
|
||||
'attachment' => self::content('post_link_url_page', '{"post_id":"667"}'),
|
||||
'overflowing id' => self::content('post_link_url_page', '{"post_id":"99999999999999999999"}'),
|
||||
'padded id' => self::content('post_link_url_page', '{"post_id":"0840"}'),
|
||||
'float id' => self::content('post_link_url_page', '{"post_id":12.0}'),
|
||||
'bool id' => self::content('post_link_url_page', '{"post_id":true}'),
|
||||
];
|
||||
foreach ($refused as $case => $value) {
|
||||
try {
|
||||
$ref->canonical($value, $sanitizer, true);
|
||||
self::fail($case . ' was accepted');
|
||||
} catch (InvalidArgumentException $e) {
|
||||
self::assertStringContainsString('Beitrags-ID', $e->getMessage(), $case);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Ruling S37/P10: select_post outside an internal link stays "a post the user may read", of any type. */
|
||||
public function testOtherPostSettingsOnlyNeedAReadablePost(): void
|
||||
{
|
||||
$ref = self::ref(['evil' => ['p' => 'select_post']]);
|
||||
$sanitizer = ComposeFixture::sanitizer();
|
||||
|
||||
self::assertSame(
|
||||
self::content('evil', '{"p":"840"}'),
|
||||
$ref->canonical(self::content('evil', '{"p":"840"}'), $sanitizer)
|
||||
);
|
||||
foreach (['"666"', '"0840"', '"99999999999999999999"'] as $id) {
|
||||
try {
|
||||
$ref->canonical(self::content('evil', '{"p":' . $id . '}'), $sanitizer);
|
||||
self::fail($id . ' was accepted');
|
||||
} catch (InvalidArgumentException $e) {
|
||||
self::assertStringContainsString('Beitrags-ID', $e->getMessage(), $id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** E13a: an internal link (post_link_url_<type>) is a URL – refused in every other field. */
|
||||
public function testInternalLinksOnlyInUrlFields(): void
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user