refactor: PostRow::update and PostGuard::assertNoMissedSchedule (M5)

- PostRow::update(id, columns, failure) / ::save(): the slashed wp_update_post of
  internal row writes, refusals as RuntimeException '<failure>: <why>'. Used by
  ContentUpdate::restoreRow, PostCloner::updateRow, MediaMetaWriter apply/restore.
- PostGuard::assertNoMissedSchedule(postId, message) replaces the re-read + check in
  ContentUpdate::restoreRow, PostCloner and DiviSaver::restore (DiviSaver keeps its
  own kses window; M4).
- PostCloner::restore uses Rollback::attempt.
Log messages unchanged.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-26 17:42:33 +02:00
co-authored by Claude Opus 5.5
parent 8e5ba9eac4
commit 4114bdb805
8 changed files with 140 additions and 49 deletions
@@ -148,4 +148,20 @@ final class PostGuardTest extends TestCase
Functions\when('current_user_can')->justReturn(false);
self::assertSame('lit_forbidden', PostGuard::postType('page', $this->schema(), 'create_posts')->get_error_code());
}
public function testAssertNoMissedScheduleRefusesAMissedScheduleWithTheCallersMessage(): void
{
Functions\when('get_post')->alias(static fn (int $id): ?WP_Post => match ($id) {
5 => new WP_Post(['ID' => 5, 'post_status' => 'future', 'post_date_gmt' => '2020-01-01 09:00:00']),
6 => new WP_Post(['ID' => 6, 'post_status' => 'publish']),
default => null,
});
PostGuard::assertNoMissedSchedule(6, 'nie');
PostGuard::assertNoMissedSchedule(7, 'nie');
$this->expectException(\RuntimeException::class);
$this->expectExceptionMessage('Post 5 not written');
PostGuard::assertNoMissedSchedule(5, 'Post 5 not written');
}
}
@@ -0,0 +1,42 @@
<?php
declare(strict_types=1);
namespace LIT\MCP\Tests\Unit\Integrations\WordPress;
use Brain\Monkey\Functions;
use LIT\MCP\Integrations\WordPress\PostRow;
use LIT\MCP\Tests\Unit\TestCase;
use RuntimeException;
use WP_Error;
final class PostRowTest extends TestCase
{
public function testUpdateSavesTheSlashedColumnsWithTheId(): void
{
Functions\when('wp_slash')->alias(static fn (array $data): array => $data + ['slashed' => 1]);
Functions\expect('wp_update_post')->once()
->with(['post_title' => 'A', 'ID' => 5, 'slashed' => 1], true)
->andReturn(5);
PostRow::update(5, ['post_title' => 'A'], 'nie');
}
public function testUpdateThrowsTheFailureWithWordPressReason(): void
{
Functions\when('wp_update_post')->justReturn(new WP_Error('db', 'Datenbank weg'));
$this->expectException(RuntimeException::class);
$this->expectExceptionMessage('Post 5 could not be updated: Datenbank weg');
PostRow::update(5, ['post_title' => 'A'], 'Post 5 could not be updated');
}
public function testSaveReportsAZeroResultAsUnknownError(): void
{
Functions\when('wp_update_post')->justReturn(0);
self::assertSame('unknown error', PostRow::save(5, ['post_title' => 'A']));
Functions\when('wp_update_post')->justReturn(5);
self::assertNull(PostRow::save(5, ['post_title' => 'A']));
}
}