fix: detach meldet nicht „alles erledigt“, solange nicht lesbare Fundstellen Verweise enthalten können; PageRewriter::apply liefert hidden_count; Tests für Sperre durch nicht lesbare Seiten und post_ids über der Obergrenze

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
Jan-Niclas Loosen
2026-10-18 17:38:01 +02:00
co-authored by Claude Sonnet 5.5
parent b805ed64dd
commit 06398242d6
7 changed files with 132 additions and 11 deletions
@@ -303,6 +303,36 @@ final class DiviDesignDetachAbilityTest extends TestCase
);
}
public function testUnreadablePostsKeepTheDeleteHintBack(): void
{
$pages = Mockery::mock(PageRewriter::class);
$pages->expects('apply')->andReturn(PageRewriteReportTest::applied(1, 0, [], 3));
$result = $this->ability($pages)->execute([
'preset' => ['module' => 'button', 'preset' => 'CTA primär'],
'confirm' => true,
]);
self::assertStringNotContainsString('lit/divi-presets-delete', $result['summary']);
self::assertStringNotContainsString('erledigt', $result['summary']);
self::assertStringContainsString('3 für diesen Zugang nicht sichtbare Fundstellen', $result['summary']);
self::assertSame(3, $result['hidden_count']);
}
public function testNoUnreadablePostsKeepTheDeleteHint(): void
{
$pages = Mockery::mock(PageRewriter::class);
$pages->expects('apply')->andReturn(PageRewriteReportTest::applied(1, 0));
$result = $this->ability($pages)->execute([
'preset' => ['module' => 'button', 'preset' => 'CTA primär'],
'confirm' => true,
]);
self::assertStringContainsString('lit/divi-presets-delete', $result['summary']);
self::assertStringNotContainsString('nicht sichtbare', $result['summary']);
}
public function testRemainingPagesAskForAnotherCallWithoutTheDeleteHint(): void
{
$pages = Mockery::mock(PageRewriter::class);
@@ -45,14 +45,20 @@ final class PageRewriteReportTest extends TestCase
* @param list<array{post_id: int, reason: string}> $skipped
* @return array<string, mixed>
*/
public static function applied(int $saved, int $remaining, array $skipped = []): array
public static function applied(int $saved, int $remaining, array $skipped = [], int $hidden = 0): array
{
$rows = [];
for ($i = 0; $i < $saved; ++$i) {
$rows[] = ['post_id' => 12 + $i, 'revision_id' => 900 + $i, 'nodes' => 2];
}
return ['saved' => $rows, 'remaining' => $remaining, 'warnings' => [], 'skipped' => $skipped];
return [
'saved' => $rows,
'remaining' => $remaining,
'warnings' => [],
'skipped' => $skipped,
'hidden_count' => $hidden,
];
}
public function testEmptyMeansNothingToWriteNothingBlockedNothingHidden(): void
@@ -618,5 +618,60 @@ final class PageRewriterTest extends TestCase
self::assertSame(1, $preview['hidden_count']);
self::assertSame([[101, SaveScope::Page]], $this->saved);
self::assertSame([], $result['skipped']);
self::assertSame(1, $result['hidden_count'], 'detach must not say "all done" with unreadable usages');
}
/** Unreadable live usages the caller may not edit refuse the call (forbidden) as a count; preview lists them. */
public function testUnreadableBlockedLivePagesRefuseTheCallAsACount(): void
{
$report = new UsageReport(2, [], 1, 2, [102], 2, false);
$rewriter = $this->rewriter(
[
self::page(101, self::layout(self::BUTTON), ['post_status' => 'publish']),
self::page(102, self::layout(self::BUTTON), ['post_status' => 'publish']),
],
$report
);
$preview = $rewriter->preview(self::query(), self::assign(), null);
self::assertSame([102], $preview['blocked_ids']);
self::assertSame(2, $preview['blocked_hidden_count']);
$error = self::assertToolError(
$rewriter->apply(self::ABILITY, self::query(), self::assign(), null, self::SUMMARY),
'forbidden'
);
self::assertSame([102], $error['blocked_ids']);
self::assertSame(2, $error['blocked_hidden_count']);
self::assertStringContainsString('2 Einträge, die dieses Konto nicht lesen darf', $error['message']);
self::assertSame([], $this->saved);
self::assertSame([], $this->log->records);
}
/**
* Above HARD_CAP live usages the per-row edit check does not run (blocked stays empty): post_ids are not refused,
* and a named live page the caller may not edit is skipped by loadWritable() instead of forbidden.
*/
public function testPostIdsAboveTheHardCapAreNotRefusedAndAnUneditablePageIsSkipped(): void
{
$rewriter = $this->rewriter(
[
self::page(101, self::layout(self::BUTTON), ['post_status' => 'publish']),
self::page(102, self::layout(self::BUTTON), ['post_status' => 'publish']),
],
self::report(GlobalUsages::HARD_CAP + 1, [], GlobalUsages::HARD_CAP + 1, true)
);
Functions\when('current_user_can')->alias(
static fn (string $cap, mixed ...$args): bool => ! ($cap === 'edit_post' && ($args[0] ?? null) === 101)
);
self::assertToolError($rewriter->preview(self::query(), self::assign(), null), 'unsupported');
$preview = $rewriter->preview(self::query(), self::assign(), [101, 102]);
$result = $rewriter->apply(self::ABILITY, self::query(), self::assign(), [101, 102], self::SUMMARY);
self::assertSame([], $preview['blocked_ids']);
self::assertSame([102], array_column($result['saved'], 'post_id'));
self::assertSame([101], array_column($result['skipped'], 'post_id'));
self::assertSame([[102, SaveScope::Page]], $this->saved);
}
}