test: FakeChangeLog and SchemaFixture instead of repeated mocks (T2)
- tests/Support/FakeChangeLog extends ChangeLog: records record()/recordPartial() calls, increasing ids, optional failure; new FakeChangeLog(id) / partialsOnly() / any(id) / forbidden() mirror what the replaced mocks allowed. assertRecorded() / assertPartials() check count and the named arguments. Calls a fake does not allow throw and are also verified in TestCase::tearDown (one assertion per test that uses a fake), so swallowed change-log calls still fail like a never() expectation. - All ChangeLog mocks of ability/integration tests replaced (the admin tests that stub query/purge/clear keep their mocks); expectException tests that checked the partial log now catch and assert. - SchemaFixture::managed(?divi) replaces the 21 isManaged-only ContentSchema mocks; DiviFixtures::schema() uses it. Tests 1397 -> 1404 (FakeChangeLogTest); no test has fewer assertions. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -5,10 +5,10 @@ declare(strict_types=1);
|
||||
namespace LIT\MCP\Tests\Unit\Integrations\Divi;
|
||||
|
||||
use LIT\MCP\Abilities\Ability;
|
||||
use LIT\MCP\ChangeLog\ChangeLog;
|
||||
use LIT\MCP\Integrations\Divi\DiviIntegration;
|
||||
use LIT\MCP\Integrations\Divi\Pages\DiviContentComposer;
|
||||
use LIT\MCP\Integrations\WordPress\Schema\ContentSchema;
|
||||
use LIT\MCP\Tests\Support\FakeChangeLog;
|
||||
use LIT\MCP\Tests\Unit\TestCase;
|
||||
use Mockery;
|
||||
|
||||
@@ -30,7 +30,7 @@ final class DiviIntegrationTest extends TestCase
|
||||
|
||||
public function testProvidesTheDiviAbilitiesOnlyWithDivi5(): void
|
||||
{
|
||||
$integration = new DiviIntegration(Mockery::mock(ContentSchema::class), Mockery::mock(ChangeLog::class));
|
||||
$integration = new DiviIntegration(Mockery::mock(ContentSchema::class), FakeChangeLog::forbidden());
|
||||
|
||||
self::assertSame('divi', $integration->id());
|
||||
self::assertFalse($integration->isAvailable(), 'no Divi classes in unit tests');
|
||||
@@ -48,7 +48,7 @@ final class DiviIntegrationTest extends TestCase
|
||||
|
||||
public function testGivesContentCreateTheDiviShortForm(): void
|
||||
{
|
||||
$integration = new DiviIntegration(Mockery::mock(ContentSchema::class), Mockery::mock(ChangeLog::class));
|
||||
$integration = new DiviIntegration(Mockery::mock(ContentSchema::class), FakeChangeLog::forbidden());
|
||||
|
||||
$composer = $integration->contentComposer();
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ use LIT\MCP\Integrations\Divi\Pages\DiviWriter;
|
||||
use LIT\MCP\Integrations\Divi\Pages\DynamicContentMap;
|
||||
use LIT\MCP\Tests\Support\DiviFixtures;
|
||||
use LIT\MCP\Tests\Support\DiviWriterFixture;
|
||||
use LIT\MCP\Tests\Support\FakeChangeLog;
|
||||
use LIT\MCP\Tests\Unit\TestCase;
|
||||
use Mockery;
|
||||
use WP_Post;
|
||||
@@ -50,7 +51,7 @@ final class DiviWriterTest extends TestCase
|
||||
{
|
||||
$content = DiviFixtures::markup('synthetic-basic.html');
|
||||
DiviFixtures::givenPost($content);
|
||||
$writer = $this->writer(Mockery::mock(DiviSaver::class), Mockery::mock(ChangeLog::class));
|
||||
$writer = $this->writer(Mockery::mock(DiviSaver::class), FakeChangeLog::forbidden());
|
||||
|
||||
self::assertInstanceOf(DiviPage::class, $writer->page(['post_id' => 7, 'tree_rev' => Rev::of($content)]));
|
||||
self::assertSame('lit_rev_mismatch', $writer->page(['post_id' => 7])->get_error_code());
|
||||
@@ -66,7 +67,7 @@ final class DiviWriterTest extends TestCase
|
||||
$writer = new DiviWriter(
|
||||
new DiviPageLoader(DiviFixtures::schema(false)),
|
||||
Mockery::mock(DiviSaver::class),
|
||||
Mockery::mock(ChangeLog::class),
|
||||
FakeChangeLog::forbidden(),
|
||||
Mockery::mock(DesignSystemReader::class),
|
||||
Mockery::mock(DiviComposition::class)
|
||||
);
|
||||
@@ -87,7 +88,7 @@ final class DiviWriterTest extends TestCase
|
||||
{
|
||||
$content = DiviFixtures::markup('synthetic-basic.html');
|
||||
DiviFixtures::givenPost($content);
|
||||
$writer = $this->writer(Mockery::mock(DiviSaver::class), Mockery::mock(ChangeLog::class));
|
||||
$writer = $this->writer(Mockery::mock(DiviSaver::class), FakeChangeLog::forbidden());
|
||||
$page = $writer->page(['post_id' => 7, 'tree_rev' => Rev::of($content)]);
|
||||
|
||||
$writer->composition($page)->placeholders();
|
||||
@@ -101,7 +102,7 @@ final class DiviWriterTest extends TestCase
|
||||
DiviFixtures::givenPost($content);
|
||||
$saver = Mockery::mock(DiviSaver::class);
|
||||
$saver->expects('save')->never();
|
||||
$writer = $this->writer($saver, Mockery::mock(ChangeLog::class));
|
||||
$writer = $this->writer($saver, FakeChangeLog::forbidden());
|
||||
$page = $writer->page(['post_id' => 7, 'tree_rev' => Rev::of($content)]);
|
||||
|
||||
$result = $writer->save('lit/divi-update', $page, new DiviChange('nichts'), []);
|
||||
@@ -122,9 +123,7 @@ final class DiviWriterTest extends TestCase
|
||||
|
||||
return ['revision_id' => 811, 'warnings' => ['vom Speichern']];
|
||||
});
|
||||
$log = Mockery::mock(ChangeLog::class);
|
||||
$log->expects('record')->with('lit/divi-update', 'page', '7', 'Divi "Start": Button geändert', 811)
|
||||
->andReturn(55);
|
||||
$log = new FakeChangeLog(55);
|
||||
$input = ['post_id' => 7, 'tree_rev' => Rev::of($content)];
|
||||
Functions\expect('do_action')->once()->with('lit_mcp_after_save', 7, 'lit/divi-update', $input);
|
||||
Functions\when('get_preview_post_link')->justReturn('https://kunde.test/?page_id=7&preview=true');
|
||||
@@ -158,6 +157,13 @@ final class DiviWriterTest extends TestCase
|
||||
self::assertContains('eigene Warnung', $result['warnings']);
|
||||
self::assertContains('vom Speichern', $result['warnings']);
|
||||
self::assertSame(Rev::ofPost(DiviFixtures::givenPost($stored)), $result['rev']);
|
||||
$log->assertRecorded([
|
||||
'ability' => 'lit/divi-update',
|
||||
'object_type' => 'page',
|
||||
'object_id' => '7',
|
||||
'summary' => 'Divi "Start": Button geändert',
|
||||
'revision_id' => 811,
|
||||
]);
|
||||
}
|
||||
|
||||
public function testFailedRollbackIsLoggedAsPartial(): void
|
||||
@@ -166,14 +172,24 @@ final class DiviWriterTest extends TestCase
|
||||
DiviFixtures::givenPost($content);
|
||||
$saver = Mockery::mock(DiviSaver::class);
|
||||
$saver->allows('save')->andThrow(WriteFailed::partial(DiviSaver::REASON, postId: 7, revisionId: 811));
|
||||
$log = Mockery::mock(ChangeLog::class);
|
||||
$log->expects('recordPartial')->with('lit/divi-delete', 'page', '7', 'Divi "Start": Änderung nur teilweise zurückgenommen', 811);
|
||||
$log = FakeChangeLog::partialsOnly();
|
||||
$writer = $this->writer($saver, $log);
|
||||
$page = $writer->page(['post_id' => 7, 'tree_rev' => Rev::of($content)]);
|
||||
$page->document->children()[0]->removeChild($page->index->find('s1'));
|
||||
|
||||
$this->expectException(WriteFailed::class);
|
||||
$writer->save('lit/divi-delete', $page, new DiviChange('s1 gelöscht'), []);
|
||||
try {
|
||||
$writer->save('lit/divi-delete', $page, new DiviChange('s1 gelöscht'), []);
|
||||
self::fail('WriteFailed expected');
|
||||
} catch (WriteFailed $e) {
|
||||
self::assertFalse($e->rolledBack);
|
||||
}
|
||||
$log->assertPartials([
|
||||
'ability' => 'lit/divi-delete',
|
||||
'object_type' => 'page',
|
||||
'object_id' => '7',
|
||||
'summary' => 'Divi "Start": Änderung nur teilweise zurückgenommen',
|
||||
'revision_id' => 811,
|
||||
]);
|
||||
}
|
||||
|
||||
public function testCleanFailureIsNotLogged(): void
|
||||
@@ -182,14 +198,18 @@ final class DiviWriterTest extends TestCase
|
||||
DiviFixtures::givenPost($content);
|
||||
$saver = Mockery::mock(DiviSaver::class);
|
||||
$saver->allows('save')->andThrow(WriteFailed::rolledBack(DiviSaver::REASON, postId: 7, revisionId: 811));
|
||||
$log = Mockery::mock(ChangeLog::class);
|
||||
$log->expects('recordPartial')->never();
|
||||
$log->expects('record')->never();
|
||||
$log = FakeChangeLog::forbidden();
|
||||
$writer = $this->writer($saver, $log);
|
||||
$page = $writer->page(['post_id' => 7, 'tree_rev' => Rev::of($content)]);
|
||||
$page->document->children()[0]->removeChild($page->index->find('s1'));
|
||||
|
||||
$this->expectException(WriteFailed::class);
|
||||
$writer->save('lit/divi-delete', $page, new DiviChange('s1 gelöscht'), []);
|
||||
try {
|
||||
$writer->save('lit/divi-delete', $page, new DiviChange('s1 gelöscht'), []);
|
||||
self::fail('WriteFailed expected');
|
||||
} catch (WriteFailed $e) {
|
||||
self::assertTrue($e->rolledBack);
|
||||
}
|
||||
$log->assertRecorded();
|
||||
$log->assertPartials();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ use Brain\Monkey\Functions;
|
||||
use LIT\MCP\ChangeLog\ChangeLog;
|
||||
use LIT\MCP\Integrations\Media\MediaDeleteAbility;
|
||||
use LIT\MCP\Integrations\Media\MediaUsageFinder;
|
||||
use LIT\MCP\Tests\Support\FakeChangeLog;
|
||||
use LIT\MCP\Tests\Unit\TestCase;
|
||||
use Mockery;
|
||||
use RuntimeException;
|
||||
@@ -38,7 +39,7 @@ final class MediaDeleteAbilityTest extends TestCase
|
||||
{
|
||||
Functions\expect('wp_delete_attachment')->never();
|
||||
|
||||
$result = $this->ability(self::USAGE, Mockery::mock(ChangeLog::class))->execute(['id' => 33]);
|
||||
$result = $this->ability(self::USAGE, FakeChangeLog::forbidden())->execute(['id' => 33]);
|
||||
|
||||
self::assertSame('lit_confirm_required', $result->get_error_code());
|
||||
self::assertStringContainsString('endgültig', $result->get_error_message());
|
||||
@@ -48,7 +49,7 @@ final class MediaDeleteAbilityTest extends TestCase
|
||||
|
||||
public function testConfirmationMentionsTheTrashWhenMediaTrashIsOn(): void
|
||||
{
|
||||
$result = $this->ability([], Mockery::mock(ChangeLog::class), true)->execute(['id' => 33, 'confirm' => false]);
|
||||
$result = $this->ability([], FakeChangeLog::forbidden(), true)->execute(['id' => 33, 'confirm' => false]);
|
||||
|
||||
self::assertSame('lit_confirm_required', $result->get_error_code());
|
||||
self::assertStringContainsString('Papierkorb', $result->get_error_message());
|
||||
@@ -58,7 +59,7 @@ final class MediaDeleteAbilityTest extends TestCase
|
||||
{
|
||||
Functions\expect('wp_delete_attachment')->never();
|
||||
|
||||
$result = $this->ability(self::USAGE, Mockery::mock(ChangeLog::class))->execute(['id' => 33, 'confirm' => true]);
|
||||
$result = $this->ability(self::USAGE, FakeChangeLog::forbidden())->execute(['id' => 33, 'confirm' => true]);
|
||||
|
||||
self::assertSame('lit_in_use', $result->get_error_code());
|
||||
self::assertSame(self::USAGE, $result->get_error_data()['usages']);
|
||||
@@ -68,7 +69,7 @@ final class MediaDeleteAbilityTest extends TestCase
|
||||
{
|
||||
Functions\expect('wp_delete_attachment')->never();
|
||||
|
||||
$result = $this->ability(self::POSSIBLE, Mockery::mock(ChangeLog::class))->execute(['id' => 33, 'confirm' => true]);
|
||||
$result = $this->ability(self::POSSIBLE, FakeChangeLog::forbidden())->execute(['id' => 33, 'confirm' => true]);
|
||||
|
||||
self::assertSame('lit_in_use', $result->get_error_code());
|
||||
}
|
||||
@@ -76,25 +77,35 @@ final class MediaDeleteAbilityTest extends TestCase
|
||||
public function testForceDeletesUsedMedia(): void
|
||||
{
|
||||
Functions\expect('wp_delete_attachment')->once()->with(33, false)->andReturn(new WP_Post(['ID' => 33]));
|
||||
$log = Mockery::mock(ChangeLog::class);
|
||||
$log->expects('record')->with('lit/media-delete', 'attachment', '33', 'Medium "Foto" gelöscht')->andReturn(50);
|
||||
$log = new FakeChangeLog(50);
|
||||
|
||||
$result = $this->ability(self::USAGE, $log)->execute(['id' => 33, 'confirm' => true, 'force' => true]);
|
||||
|
||||
self::assertSame(['id' => '33', 'type' => 'attachment', 'action' => 'deleted', 'label' => 'Foto'], $result['changed'][0]);
|
||||
self::assertSame(50, $result['log_id']);
|
||||
self::assertSame(self::USAGE, $result['usages']);
|
||||
$log->assertRecorded([
|
||||
'ability' => 'lit/media-delete',
|
||||
'object_type' => 'attachment',
|
||||
'object_id' => '33',
|
||||
'summary' => 'Medium "Foto" gelöscht',
|
||||
]);
|
||||
}
|
||||
|
||||
public function testUnusedMediaGoesToTheTrashWhenMediaTrashIsOn(): void
|
||||
{
|
||||
Functions\expect('wp_delete_attachment')->once()->with(33, false)->andReturn(new WP_Post(['ID' => 33]));
|
||||
$log = Mockery::mock(ChangeLog::class);
|
||||
$log->expects('record')->with('lit/media-delete', 'attachment', '33', 'Medium "Foto" in den Papierkorb gelegt')->andReturn(51);
|
||||
$log = new FakeChangeLog(51);
|
||||
|
||||
$result = $this->ability([], $log, true)->execute(['id' => 33, 'confirm' => true]);
|
||||
|
||||
self::assertSame('trashed', $result['changed'][0]['action']);
|
||||
$log->assertRecorded([
|
||||
'ability' => 'lit/media-delete',
|
||||
'object_type' => 'attachment',
|
||||
'object_id' => '33',
|
||||
'summary' => 'Medium "Foto" in den Papierkorb gelegt',
|
||||
]);
|
||||
}
|
||||
|
||||
public function testRefusedDeleteWithTheAttachmentIntactIsAWriteFailure(): void
|
||||
@@ -102,7 +113,7 @@ final class MediaDeleteAbilityTest extends TestCase
|
||||
Functions\when('get_post_meta')->justReturn('2026/09/foto.jpg');
|
||||
Functions\expect('wp_delete_attachment')->once()->andReturn(false);
|
||||
|
||||
$result = $this->ability([], Mockery::mock(ChangeLog::class))->execute(['id' => 33, 'confirm' => true]);
|
||||
$result = $this->ability([], FakeChangeLog::forbidden())->execute(['id' => 33, 'confirm' => true]);
|
||||
|
||||
self::assertSame('lit_write_failed', $result->get_error_code());
|
||||
}
|
||||
@@ -118,13 +129,13 @@ final class MediaDeleteAbilityTest extends TestCase
|
||||
|
||||
return null;
|
||||
});
|
||||
$log = Mockery::mock(ChangeLog::class);
|
||||
$log->expects('recordPartial')->once()->with('lit/media-delete', 'attachment', '33', Mockery::type('string'));
|
||||
$log = FakeChangeLog::partialsOnly();
|
||||
|
||||
$result = $this->ability([], $log)->execute(['id' => 33, 'confirm' => true]);
|
||||
|
||||
self::assertSame('lit_partial_write', $result->get_error_code());
|
||||
self::assertSame(33, $result->get_error_data()['attachment_id']);
|
||||
$log->assertPartials(['ability' => 'lit/media-delete', 'object_type' => 'attachment', 'object_id' => '33']);
|
||||
}
|
||||
|
||||
public function testADatabaseErrorInTheUsageCheckRefusesWithoutForce(): void
|
||||
@@ -138,7 +149,7 @@ final class MediaDeleteAbilityTest extends TestCase
|
||||
$db->allows('get_results')->andReturn(null);
|
||||
$ability = new MediaDeleteAbility(
|
||||
new MediaUsageFinder(static fn (): array => [], $db),
|
||||
Mockery::mock(ChangeLog::class),
|
||||
FakeChangeLog::forbidden(),
|
||||
static fn (): bool => false
|
||||
);
|
||||
|
||||
@@ -158,8 +169,7 @@ final class MediaDeleteAbilityTest extends TestCase
|
||||
public function testChangeLogFailureIsOnlyAWarning(): void
|
||||
{
|
||||
Functions\expect('wp_delete_attachment')->once()->andReturn(new WP_Post(['ID' => 33]));
|
||||
$log = Mockery::mock(ChangeLog::class);
|
||||
$log->expects('record')->andThrow(new RuntimeException('db down'));
|
||||
$log = new FakeChangeLog(1, new RuntimeException('db down'));
|
||||
|
||||
$file = (string) tempnam(sys_get_temp_dir(), 'lit-mcp-log');
|
||||
$previous = ini_set('error_log', $file);
|
||||
@@ -173,6 +183,7 @@ final class MediaDeleteAbilityTest extends TestCase
|
||||
self::assertSame('deleted', $result['changed'][0]['action']);
|
||||
self::assertNull($result['log_id']);
|
||||
self::assertCount(1, $result['warnings']);
|
||||
$log->assertRecorded([]);
|
||||
}
|
||||
|
||||
public function testTrashedAttachmentIsRefused(): void
|
||||
@@ -180,7 +191,7 @@ final class MediaDeleteAbilityTest extends TestCase
|
||||
Functions\when('get_post')->justReturn(new WP_Post(['ID' => 33, 'post_type' => 'attachment', 'post_status' => 'trash']));
|
||||
Functions\expect('wp_delete_attachment')->never();
|
||||
|
||||
$ability = $this->ability([], Mockery::mock(ChangeLog::class));
|
||||
$ability = $this->ability([], FakeChangeLog::forbidden());
|
||||
|
||||
self::assertSame('lit_validation_failed', $ability->permission(['id' => 33])->get_error_code());
|
||||
self::assertSame('lit_validation_failed', $ability->execute(['id' => 33, 'confirm' => true])->get_error_code());
|
||||
@@ -190,14 +201,14 @@ final class MediaDeleteAbilityTest extends TestCase
|
||||
{
|
||||
Functions\when('current_user_can')->alias(static fn (string $cap, int $id): bool => ! ($cap === 'delete_post' && $id === 33));
|
||||
|
||||
$result = $this->ability([], Mockery::mock(ChangeLog::class))->permission(['id' => 33]);
|
||||
$result = $this->ability([], FakeChangeLog::forbidden())->permission(['id' => 33]);
|
||||
|
||||
self::assertSame('lit_forbidden', $result->get_error_code());
|
||||
}
|
||||
|
||||
public function testIsDestructiveAndDescribesWhatTheUsageCheckMisses(): void
|
||||
{
|
||||
$ability = $this->ability([], Mockery::mock(ChangeLog::class));
|
||||
$ability = $this->ability([], FakeChangeLog::forbidden());
|
||||
|
||||
self::assertSame(['readonly' => false, 'destructive' => true, 'idempotent' => false], $ability->annotations());
|
||||
self::assertFalse($ability->isDirect());
|
||||
|
||||
@@ -5,10 +5,10 @@ declare(strict_types=1);
|
||||
namespace LIT\MCP\Tests\Unit\Integrations\Media;
|
||||
|
||||
use LIT\MCP\Abilities\Ability;
|
||||
use LIT\MCP\ChangeLog\ChangeLog;
|
||||
use LIT\MCP\Integrations\Media\MediaIntegration;
|
||||
use LIT\MCP\Integrations\WordPress\Schema\ContentSchema;
|
||||
use LIT\MCP\Limits;
|
||||
use LIT\MCP\Tests\Support\FakeChangeLog;
|
||||
use LIT\MCP\Tests\Unit\TestCase;
|
||||
use Mockery;
|
||||
|
||||
@@ -28,7 +28,7 @@ final class MediaIntegrationTest extends TestCase
|
||||
|
||||
public function testProvidesTheMediaAbilities(): void
|
||||
{
|
||||
$integration = new MediaIntegration(Mockery::mock(ContentSchema::class), Mockery::mock(ChangeLog::class), new Limits());
|
||||
$integration = new MediaIntegration(Mockery::mock(ContentSchema::class), FakeChangeLog::forbidden(), new Limits());
|
||||
|
||||
self::assertSame('media', $integration->id());
|
||||
self::assertTrue($integration->isAvailable());
|
||||
|
||||
@@ -8,8 +8,8 @@ use Brain\Monkey\Functions;
|
||||
use LIT\MCP\Abilities\WriteFailed;
|
||||
use LIT\MCP\ChangeLog\ChangeLog;
|
||||
use LIT\MCP\Integrations\Media\MediaUpdateAbility;
|
||||
use LIT\MCP\Tests\Support\FakeChangeLog;
|
||||
use LIT\MCP\Tests\Unit\TestCase;
|
||||
use Mockery;
|
||||
use RuntimeException;
|
||||
use WP_Error;
|
||||
use WP_Post;
|
||||
@@ -53,25 +53,15 @@ final class MediaUpdateAbilityTest extends TestCase
|
||||
});
|
||||
}
|
||||
|
||||
private function log(int ...$ids): ChangeLog
|
||||
/** For paths that must not log. */
|
||||
private function log(): ChangeLog
|
||||
{
|
||||
$log = Mockery::mock(ChangeLog::class);
|
||||
if ($ids !== []) {
|
||||
$log->expects('record')->times(count($ids))->andReturn(...$ids);
|
||||
}
|
||||
|
||||
return $log;
|
||||
return FakeChangeLog::forbidden();
|
||||
}
|
||||
|
||||
public function testUpdatesEveryItemAndReportsPerItem(): void
|
||||
{
|
||||
$log = Mockery::mock(ChangeLog::class);
|
||||
$log->expects('record')
|
||||
->with('lit/media-update', 'attachment', '33', 'Metadaten von "Foto" geändert: alt, caption')
|
||||
->andReturn(41);
|
||||
$log->expects('record')
|
||||
->with('lit/media-update', 'attachment', '34', 'Metadaten von "Logo" geändert: title')
|
||||
->andReturn(42);
|
||||
$log = new FakeChangeLog(41);
|
||||
|
||||
$result = (new MediaUpdateAbility($log))->execute(['items' => [
|
||||
['id' => 33, 'alt' => 'Team vor dem Haus', 'caption' => 'Unser <script>x</script>Team'],
|
||||
@@ -84,6 +74,12 @@ final class MediaUpdateAbilityTest extends TestCase
|
||||
self::assertSame(42, $result['results'][1]['log_id']);
|
||||
self::assertSame(['id' => '34', 'type' => 'attachment', 'action' => 'updated', 'label' => 'Firmenlogo'], $result['changed'][1]);
|
||||
self::assertSame('2 von 2 Medien aktualisiert.', $result['summary']);
|
||||
$log->assertRecorded(
|
||||
['ability' => 'lit/media-update', 'object_type' => 'attachment', 'object_id' => '33',
|
||||
'summary' => 'Metadaten von "Foto" geändert: alt, caption'],
|
||||
['ability' => 'lit/media-update', 'object_type' => 'attachment', 'object_id' => '34',
|
||||
'summary' => 'Metadaten von "Logo" geändert: title']
|
||||
);
|
||||
}
|
||||
|
||||
public function testAnInvalidItemRefusesTheWholeBatchAndNamesEveryFailure(): void
|
||||
@@ -226,8 +222,7 @@ final class MediaUpdateAbilityTest extends TestCase
|
||||
|
||||
return true;
|
||||
});
|
||||
$log = Mockery::mock(ChangeLog::class);
|
||||
$log->expects('recordPartial')->once()->with('lit/media-update', 'attachment', '33', Mockery::type('string'));
|
||||
$log = FakeChangeLog::partialsOnly();
|
||||
|
||||
try {
|
||||
(new MediaUpdateAbility($log))->execute(['items' => [
|
||||
@@ -241,12 +236,12 @@ final class MediaUpdateAbilityTest extends TestCase
|
||||
self::assertSame([33], $error->get_error_data()['changed_ids']);
|
||||
self::assertStringContainsString('33', $error->get_error_message());
|
||||
}
|
||||
$log->assertPartials(['ability' => 'lit/media-update', 'object_type' => 'attachment', 'object_id' => '33']);
|
||||
}
|
||||
|
||||
public function testChangeLogFailureIsOnlyAWarning(): void
|
||||
{
|
||||
$log = Mockery::mock(ChangeLog::class);
|
||||
$log->expects('record')->andThrow(new RuntimeException('db down'));
|
||||
$log = new FakeChangeLog(1, new RuntimeException('db down'));
|
||||
// error_log() is a PHP internal and cannot be stubbed; redirect it to a temp file instead.
|
||||
$file = (string) tempnam(sys_get_temp_dir(), 'lit-mcp-log');
|
||||
$previous = ini_set('error_log', $file);
|
||||
@@ -260,6 +255,7 @@ final class MediaUpdateAbilityTest extends TestCase
|
||||
self::assertTrue($result['results'][0]['ok']);
|
||||
self::assertNull($result['results'][0]['log_id']);
|
||||
self::assertCount(1, $result['warnings']);
|
||||
$log->assertRecorded([]);
|
||||
}
|
||||
|
||||
public function testIsIdempotentIndirectAndNotDestructive(): void
|
||||
|
||||
@@ -13,8 +13,9 @@ use LIT\MCP\Integrations\Media\MediaPresenter;
|
||||
use LIT\MCP\Integrations\Media\MediaUploadAbility;
|
||||
use LIT\MCP\Integrations\Media\MediaUploadFromUrlAbility;
|
||||
use LIT\MCP\Integrations\Media\MediaUploads;
|
||||
use LIT\MCP\Integrations\WordPress\Schema\ContentSchema;
|
||||
use LIT\MCP\Limits;
|
||||
use LIT\MCP\Tests\Support\FakeChangeLog;
|
||||
use LIT\MCP\Tests\Support\SchemaFixture;
|
||||
use LIT\MCP\Tests\Unit\TestCase;
|
||||
use Mockery;
|
||||
use RuntimeException;
|
||||
@@ -26,10 +27,9 @@ final class MediaUploadAbilitiesTest extends TestCase
|
||||
{
|
||||
$presenter = Mockery::mock(MediaPresenter::class);
|
||||
$presenter->allows('summary')->andReturn(['id' => 55, 'title' => 'Logo']);
|
||||
$schema = Mockery::mock(ContentSchema::class);
|
||||
$schema->allows('isManaged')->andReturn(true);
|
||||
$schema = SchemaFixture::managed();
|
||||
|
||||
return new MediaUploads($presenter, $log ?? Mockery::mock(ChangeLog::class), $schema);
|
||||
return new MediaUploads($presenter, $log ?? FakeChangeLog::forbidden(), $schema);
|
||||
}
|
||||
|
||||
private function savedAttachment(): void
|
||||
@@ -43,8 +43,7 @@ final class MediaUploadAbilitiesTest extends TestCase
|
||||
$this->savedAttachment();
|
||||
$importer = Mockery::mock(MediaImporter::class);
|
||||
$importer->expects('fromUrl')->with('https://example.com/logo.png', null, ['alt' => 'Logo'])->andReturn(55);
|
||||
$log = Mockery::mock(ChangeLog::class);
|
||||
$log->expects('record')->with('lit/media-upload-from-url', 'attachment', '55', Mockery::type('string'))->andReturn(3);
|
||||
$log = new FakeChangeLog(3);
|
||||
|
||||
$result = (new MediaUploadFromUrlAbility($importer, $this->uploads($log)))
|
||||
->execute(['url' => 'https://example.com/logo.png', 'alt' => 'Logo']);
|
||||
@@ -54,6 +53,11 @@ final class MediaUploadAbilitiesTest extends TestCase
|
||||
self::assertSame(3, $result['log_id']);
|
||||
self::assertSame('https://kunde.de/wp-admin/post.php?post=55&action=edit', $result['edit_url']);
|
||||
self::assertSame([], $result['warnings']);
|
||||
$log->assertRecorded([
|
||||
'ability' => 'lit/media-upload-from-url',
|
||||
'object_type' => 'attachment',
|
||||
'object_id' => '55',
|
||||
]);
|
||||
}
|
||||
|
||||
public function testBase64UploadPassesFilenameDataAndMeta(): void
|
||||
@@ -61,14 +65,14 @@ final class MediaUploadAbilitiesTest extends TestCase
|
||||
$this->savedAttachment();
|
||||
$importer = Mockery::mock(MediaImporter::class);
|
||||
$importer->expects('fromBase64')->with('AAAA', 'x.png', ['title' => 'Logo', 'post_id' => 5])->andReturn(55);
|
||||
$log = Mockery::mock(ChangeLog::class);
|
||||
$log->expects('record')->with('lit/media-upload', 'attachment', '55', Mockery::type('string'))->andReturn(4);
|
||||
$log = new FakeChangeLog(4);
|
||||
|
||||
$result = (new MediaUploadAbility($importer, $this->uploads($log), new Limits()))
|
||||
->execute(['filename' => 'x.png', 'data' => 'AAAA', 'title' => 'Logo', 'post_id' => 5]);
|
||||
|
||||
self::assertTrue($result['ok']);
|
||||
self::assertSame(4, $result['log_id']);
|
||||
$log->assertRecorded(['ability' => 'lit/media-upload', 'object_type' => 'attachment', 'object_id' => '55']);
|
||||
}
|
||||
|
||||
public function testAFailingChangeLogIsOnlyAWarning(): void
|
||||
@@ -76,8 +80,7 @@ final class MediaUploadAbilitiesTest extends TestCase
|
||||
$this->savedAttachment();
|
||||
$importer = Mockery::mock(MediaImporter::class);
|
||||
$importer->allows('fromUrl')->andReturn(55);
|
||||
$log = Mockery::mock(ChangeLog::class);
|
||||
$log->allows('record')->andThrow(new RuntimeException('db down'));
|
||||
$log = new FakeChangeLog(1, new RuntimeException('db down'));
|
||||
// error_log() is a PHP internal and cannot be stubbed; redirect it to a temp file instead.
|
||||
$file = (string) tempnam(sys_get_temp_dir(), 'lit-log');
|
||||
$previous = ini_set('error_log', $file);
|
||||
@@ -111,11 +114,19 @@ final class MediaUploadAbilitiesTest extends TestCase
|
||||
$failure = WriteFailed::partial('Alt-Text fehlt.', postId: 55);
|
||||
$importer = Mockery::mock(MediaImporter::class);
|
||||
$importer->allows('fromUrl')->andThrow($failure);
|
||||
$log = Mockery::mock(ChangeLog::class);
|
||||
$log->expects('recordPartial')->with('lit/media-upload-from-url', 'attachment', '55', Mockery::type('string'));
|
||||
$log = FakeChangeLog::partialsOnly();
|
||||
|
||||
$this->expectExceptionObject($failure);
|
||||
(new MediaUploadFromUrlAbility($importer, $this->uploads($log)))->execute(['url' => 'https://example.com/a.png']);
|
||||
try {
|
||||
(new MediaUploadFromUrlAbility($importer, $this->uploads($log)))->execute(['url' => 'https://example.com/a.png']);
|
||||
self::fail('WriteFailed expected');
|
||||
} catch (WriteFailed $e) {
|
||||
self::assertSame($failure, $e);
|
||||
}
|
||||
$log->assertPartials([
|
||||
'ability' => 'lit/media-upload-from-url',
|
||||
'object_type' => 'attachment',
|
||||
'object_id' => '55',
|
||||
]);
|
||||
}
|
||||
|
||||
public function testPermissionNeedsUploadRightsAndEditRightsOnTheParent(): void
|
||||
|
||||
@@ -13,6 +13,8 @@ use LIT\MCP\ChangeLog\ChangeLog;
|
||||
use LIT\MCP\Integrations\WordPress\Content\ContentCreateAbility;
|
||||
use LIT\MCP\Integrations\WordPress\Content\PostWriter;
|
||||
use LIT\MCP\Integrations\WordPress\Schema\ContentSchema;
|
||||
use LIT\MCP\Tests\Support\FakeChangeLog;
|
||||
use LIT\MCP\Tests\Support\SchemaFixture;
|
||||
use LIT\MCP\Tests\Unit\TestCase;
|
||||
use Mockery;
|
||||
use Mockery\MockInterface;
|
||||
@@ -27,8 +29,7 @@ final class ContentCreateAbilityTest extends TestCase
|
||||
{
|
||||
Functions\when('get_post_type_object')->justReturn((object) ['cap' => (object) ['create_posts' => 'edit_pages']]);
|
||||
Functions\when('current_user_can')->justReturn(true);
|
||||
$schema = Mockery::mock(ContentSchema::class);
|
||||
$schema->allows('isManaged')->andReturn(true);
|
||||
$schema = SchemaFixture::managed();
|
||||
|
||||
return $schema;
|
||||
}
|
||||
@@ -72,7 +73,7 @@ final class ContentCreateAbilityTest extends TestCase
|
||||
$writer->allows('prepare')->andReturn(Errors::invalidInput('ungültig', ['fields.role' => 'Pflichtfeld fehlt.']));
|
||||
Functions\expect('wp_insert_post')->never();
|
||||
|
||||
$result = (new ContentCreateAbility($this->schema(), $writer, Mockery::mock(ChangeLog::class)))
|
||||
$result = (new ContentCreateAbility($this->schema(), $writer, FakeChangeLog::forbidden()))
|
||||
->execute(['post_type' => 'lit_person', 'title' => 'Anna']);
|
||||
|
||||
self::assertSame('lit_validation_failed', $result->get_error_code());
|
||||
@@ -97,8 +98,7 @@ final class ContentCreateAbilityTest extends TestCase
|
||||
], true)->andReturn(42);
|
||||
Actions\expectDone('lit_mcp_after_save')->once()->with(42, 'lit/content-create', $input);
|
||||
$post = $this->stubResultLinks();
|
||||
$log = Mockery::mock(ChangeLog::class);
|
||||
$log->expects('record')->with('lit/content-create', 'lit_person', '42', 'Entwurf "Anna" angelegt', null)->andReturn(7);
|
||||
$log = new FakeChangeLog(7);
|
||||
|
||||
$result = (new ContentCreateAbility($schema, $writer, $log))->execute($input);
|
||||
|
||||
@@ -108,6 +108,13 @@ final class ContentCreateAbilityTest extends TestCase
|
||||
self::assertSame(['w'], $result['warnings']);
|
||||
self::assertStringContainsString('Entwurf', $result['summary']);
|
||||
self::assertSame(Rev::ofPost($post), $result['rev']);
|
||||
$log->assertRecorded([
|
||||
'ability' => 'lit/content-create',
|
||||
'object_type' => 'lit_person',
|
||||
'object_id' => '42',
|
||||
'summary' => 'Entwurf "Anna" angelegt',
|
||||
'revision_id' => null,
|
||||
]);
|
||||
}
|
||||
|
||||
public function testFailingExtrasDeleteCreatedTermsAndTheNewDraft(): void
|
||||
@@ -118,8 +125,7 @@ final class ContentCreateAbilityTest extends TestCase
|
||||
Functions\when('wp_insert_post')->justReturn(42);
|
||||
Functions\expect('wp_delete_post')->once()->with(42, true)->andReturn(new WP_Post(['ID' => 42]));
|
||||
Actions\expectDone('lit_mcp_after_save')->never();
|
||||
$log = Mockery::mock(ChangeLog::class);
|
||||
$log->expects('record')->never();
|
||||
$log = FakeChangeLog::forbidden();
|
||||
|
||||
$failure = $this->execute($writer, $log);
|
||||
|
||||
@@ -139,8 +145,7 @@ final class ContentCreateAbilityTest extends TestCase
|
||||
Functions\when('get_current_user_id')->justReturn(3);
|
||||
Functions\when('wp_insert_post')->justReturn(42);
|
||||
Functions\expect('wp_delete_post')->once()->with(42, true)->andReturn(new WP_Post(['ID' => 42]));
|
||||
$log = Mockery::mock(ChangeLog::class);
|
||||
$log->expects('record')->never();
|
||||
$log = FakeChangeLog::forbidden();
|
||||
|
||||
$result = (new ContentCreateAbility($this->schema(), $writer, $log))->execute(self::INPUT);
|
||||
|
||||
@@ -157,8 +162,7 @@ final class ContentCreateAbilityTest extends TestCase
|
||||
Functions\when('get_current_user_id')->justReturn(3);
|
||||
Functions\when('wp_insert_post')->justReturn(42);
|
||||
Functions\when('wp_delete_post')->justReturn(false);
|
||||
$log = Mockery::mock(ChangeLog::class);
|
||||
$log->expects('recordPartial');
|
||||
$log = FakeChangeLog::partialsOnly();
|
||||
|
||||
try {
|
||||
(new ContentCreateAbility($this->schema(), $writer, $log))->execute(self::INPUT);
|
||||
@@ -167,6 +171,7 @@ final class ContentCreateAbilityTest extends TestCase
|
||||
self::assertFalse($e->rolledBack);
|
||||
self::assertSame(42, $e->postId);
|
||||
}
|
||||
$log->assertPartials([]);
|
||||
}
|
||||
|
||||
public function testADraftThatCannotBeDeletedIsAPartialWriteAndLogged(): void
|
||||
@@ -176,16 +181,14 @@ final class ContentCreateAbilityTest extends TestCase
|
||||
$writer->expects('deleteCreatedTerms');
|
||||
Functions\when('wp_insert_post')->justReturn(42);
|
||||
Functions\when('wp_delete_post')->justReturn(false);
|
||||
$log = Mockery::mock(ChangeLog::class);
|
||||
$log->expects('recordPartial')
|
||||
->with('lit/content-create', 'lit_person', '42', Mockery::type('string'))
|
||||
->andReturn(9);
|
||||
$log = FakeChangeLog::partialsOnly();
|
||||
|
||||
$failure = $this->execute($writer, $log);
|
||||
|
||||
self::assertFalse($failure->rolledBack);
|
||||
self::assertSame(42, $failure->postId);
|
||||
self::assertStringContainsString('Eintrag 42', $failure->toError()->get_error_message());
|
||||
$log->assertPartials(['ability' => 'lit/content-create', 'object_type' => 'lit_person', 'object_id' => '42']);
|
||||
}
|
||||
|
||||
public function testLeftoverCreatedTermsMakeItAPartialWrite(): void
|
||||
@@ -195,13 +198,13 @@ final class ContentCreateAbilityTest extends TestCase
|
||||
$writer->expects('deleteCreatedTerms')->andThrow(new RuntimeException('term 15 bleibt'));
|
||||
Functions\when('wp_insert_post')->justReturn(42);
|
||||
Functions\when('wp_delete_post')->justReturn(new WP_Post(['ID' => 42]));
|
||||
$log = Mockery::mock(ChangeLog::class);
|
||||
$log->expects('recordPartial');
|
||||
$log = FakeChangeLog::partialsOnly();
|
||||
|
||||
$failure = $this->execute($writer, $log);
|
||||
|
||||
self::assertFalse($failure->rolledBack);
|
||||
self::assertStringContainsString('term 15 bleibt', $failure->getMessage());
|
||||
$log->assertPartials([]);
|
||||
}
|
||||
|
||||
public function testAnInsertThatThrowsIsAPartialWriteWithoutId(): void
|
||||
@@ -210,16 +213,14 @@ final class ContentCreateAbilityTest extends TestCase
|
||||
Functions\when('wp_insert_post')->alias(static function (): never {
|
||||
throw new RuntimeException('save_post hook kaputt');
|
||||
});
|
||||
$log = Mockery::mock(ChangeLog::class);
|
||||
$log->expects('recordPartial')
|
||||
->with('lit/content-create', 'lit_person', '', Mockery::type('string'))
|
||||
->andReturn(9);
|
||||
$log = FakeChangeLog::partialsOnly();
|
||||
|
||||
$failure = $this->execute($writer, $log);
|
||||
|
||||
self::assertFalse($failure->rolledBack);
|
||||
self::assertNull($failure->postId);
|
||||
self::assertSame('lit_partial_write', $failure->toError()->get_error_code());
|
||||
$log->assertPartials(['ability' => 'lit/content-create', 'object_type' => 'lit_person', 'object_id' => '']);
|
||||
}
|
||||
|
||||
public function testFailuresAfterTheWriteOnlyAddWarnings(): void
|
||||
@@ -231,8 +232,7 @@ final class ContentCreateAbilityTest extends TestCase
|
||||
Actions\expectDone('lit_mcp_after_save')->once()->whenHappen(static function (): void {
|
||||
throw new RuntimeException('listener kaputt');
|
||||
});
|
||||
$log = Mockery::mock(ChangeLog::class);
|
||||
$log->expects('record')->andThrow(new RuntimeException('db weg'));
|
||||
$log = new FakeChangeLog(1, new RuntimeException('db weg'));
|
||||
$file = (string) tempnam(sys_get_temp_dir(), 'lit-mcp-log');
|
||||
$previous = ini_set('error_log', $file);
|
||||
|
||||
@@ -248,12 +248,13 @@ final class ContentCreateAbilityTest extends TestCase
|
||||
self::assertStringContainsString('listener kaputt', (string) file_get_contents($file));
|
||||
self::assertStringContainsString('db weg', (string) file_get_contents($file));
|
||||
unlink($file);
|
||||
$log->assertRecorded([]);
|
||||
}
|
||||
|
||||
public function testStatusIsNotAnInputAndPermissionNeedsCreateRights(): void
|
||||
{
|
||||
$schema = $this->schema();
|
||||
$ability = new ContentCreateAbility($schema, Mockery::mock(PostWriter::class), Mockery::mock(ChangeLog::class));
|
||||
$ability = new ContentCreateAbility($schema, Mockery::mock(PostWriter::class), FakeChangeLog::forbidden());
|
||||
|
||||
self::assertArrayNotHasKey('status', $ability->inputSchema()['properties']);
|
||||
self::assertFalse($ability->inputSchema()['additionalProperties']);
|
||||
|
||||
@@ -16,6 +16,8 @@ use LIT\MCP\Integrations\WordPress\Content\ContentCreateAbility;
|
||||
use LIT\MCP\Integrations\WordPress\Content\PostWriter;
|
||||
use LIT\MCP\Integrations\WordPress\Schema\ContentSchema;
|
||||
use LIT\MCP\Tests\Support\DiviWriterFixture;
|
||||
use LIT\MCP\Tests\Support\FakeChangeLog;
|
||||
use LIT\MCP\Tests\Support\SchemaFixture;
|
||||
use LIT\MCP\Tests\Unit\TestCase;
|
||||
use Mockery;
|
||||
use Mockery\MockInterface;
|
||||
@@ -34,9 +36,7 @@ final class ContentCreateDiviTest extends TestCase
|
||||
Functions\when('get_post_type_object')->justReturn((object) ['cap' => (object) ['create_posts' => 'edit_pages']]);
|
||||
Functions\when('current_user_can')->justReturn(true);
|
||||
Functions\when('get_current_user_id')->justReturn(3);
|
||||
$schema = Mockery::mock(ContentSchema::class);
|
||||
$schema->allows('isManaged')->andReturn(true);
|
||||
$schema->allows('diviEnabled')->andReturn(true);
|
||||
$schema = SchemaFixture::managed(true);
|
||||
|
||||
return $schema;
|
||||
}
|
||||
@@ -66,9 +66,7 @@ final class ContentCreateDiviTest extends TestCase
|
||||
|
||||
private function log(): ChangeLog
|
||||
{
|
||||
$log = Mockery::mock(ChangeLog::class);
|
||||
$log->allows('record')->andReturn(9);
|
||||
$log->allows('recordPartial');
|
||||
$log = FakeChangeLog::any(9);
|
||||
|
||||
return $log;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ use Brain\Monkey\Functions;
|
||||
use LIT\MCP\Integrations\WordPress\Content\ContentGetAbility;
|
||||
use LIT\MCP\Integrations\WordPress\Content\PostPresenter;
|
||||
use LIT\MCP\Integrations\WordPress\Schema\ContentSchema;
|
||||
use LIT\MCP\Tests\Support\SchemaFixture;
|
||||
use LIT\MCP\Tests\Unit\TestCase;
|
||||
use Mockery;
|
||||
use WP_Post;
|
||||
@@ -19,8 +20,7 @@ final class ContentGetAbilityTest extends TestCase
|
||||
$post = new WP_Post(['ID' => 5, 'post_type' => 'page']);
|
||||
Functions\when('get_post')->justReturn($post);
|
||||
Functions\when('current_user_can')->justReturn(true);
|
||||
$schema = Mockery::mock(ContentSchema::class);
|
||||
$schema->allows('isManaged')->andReturn(true);
|
||||
$schema = SchemaFixture::managed();
|
||||
$presenter = Mockery::mock(PostPresenter::class);
|
||||
$presenter->expects('full')->with($post)->andReturn(['id' => 5]);
|
||||
$ability = new ContentGetAbility($schema, $presenter);
|
||||
@@ -34,8 +34,7 @@ final class ContentGetAbilityTest extends TestCase
|
||||
$post = new WP_Post(['ID' => 5, 'post_type' => 'page', 'post_status' => 'trash']);
|
||||
Functions\when('get_post')->justReturn($post);
|
||||
Functions\when('current_user_can')->justReturn(true);
|
||||
$schema = Mockery::mock(ContentSchema::class);
|
||||
$schema->allows('isManaged')->andReturn(true);
|
||||
$schema = SchemaFixture::managed();
|
||||
$presenter = Mockery::mock(PostPresenter::class);
|
||||
$presenter->expects('full')->with($post)->andReturn(['id' => 5]);
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ use LIT\MCP\Integrations\WordPress\Content\ContentQueryAbility;
|
||||
use LIT\MCP\Integrations\WordPress\Content\PostPresenter;
|
||||
use LIT\MCP\Integrations\WordPress\Schema\ContentSchema;
|
||||
use LIT\MCP\Integrations\WordPress\Schema\FieldDefinition;
|
||||
use LIT\MCP\Tests\Support\SchemaFixture;
|
||||
use LIT\MCP\Tests\Unit\TestCase;
|
||||
use Mockery;
|
||||
use WP_Post;
|
||||
@@ -241,8 +242,7 @@ final class ContentQueryAbilityTest extends TestCase
|
||||
{
|
||||
Functions\when('get_post_type_object')->justReturn((object) ['cap' => (object) ['edit_posts' => 'edit_posts']]);
|
||||
Functions\when('current_user_can')->justReturn(false);
|
||||
$schema = Mockery::mock(ContentSchema::class);
|
||||
$schema->allows('isManaged')->andReturn(true);
|
||||
$schema = SchemaFixture::managed();
|
||||
$ability = new ContentQueryAbility($schema, Mockery::mock(PostPresenter::class));
|
||||
|
||||
self::assertSame('lit_forbidden', $ability->permission(['post_type' => 'page'])->get_error_code());
|
||||
|
||||
@@ -7,6 +7,7 @@ namespace LIT\MCP\Tests\Unit\Integrations\WordPress\Content;
|
||||
use Brain\Monkey\Functions;
|
||||
use LIT\MCP\Integrations\WordPress\Content\ContentTypesAbility;
|
||||
use LIT\MCP\Integrations\WordPress\Schema\ContentSchema;
|
||||
use LIT\MCP\Tests\Support\SchemaFixture;
|
||||
use LIT\MCP\Tests\Unit\TestCase;
|
||||
use Mockery;
|
||||
use WP_Error;
|
||||
@@ -89,8 +90,7 @@ final class ContentTypesAbilityTest extends TestCase
|
||||
{
|
||||
Functions\when('get_post_type_object')->justReturn((object) ['cap' => (object) ['edit_posts' => 'edit_pages']]);
|
||||
Functions\when('current_user_can')->justReturn(false);
|
||||
$schema = Mockery::mock(ContentSchema::class);
|
||||
$schema->allows('isManaged')->andReturn(true);
|
||||
$schema = SchemaFixture::managed();
|
||||
|
||||
$result = (new ContentTypesAbility($schema))->execute(['post_type' => 'page']);
|
||||
|
||||
@@ -110,8 +110,7 @@ final class ContentTypesAbilityTest extends TestCase
|
||||
{
|
||||
Functions\when('current_user_can')->alias(static fn (string $cap): bool => $cap === 'edit_posts');
|
||||
Functions\when('get_post_type_object')->justReturn((object) ['cap' => (object) ['edit_posts' => 'edit_pages']]);
|
||||
$schema = Mockery::mock(ContentSchema::class);
|
||||
$schema->allows('isManaged')->andReturn(true);
|
||||
$schema = SchemaFixture::managed();
|
||||
|
||||
$result = (new ContentTypesAbility($schema))->permission(['post_type' => 'lit_person']);
|
||||
|
||||
@@ -123,8 +122,7 @@ final class ContentTypesAbilityTest extends TestCase
|
||||
{
|
||||
Functions\when('current_user_can')->justReturn(true);
|
||||
Functions\when('get_post_type_object')->justReturn((object) ['cap' => (object) ['edit_posts' => 'edit_posts']]);
|
||||
$schema = Mockery::mock(ContentSchema::class);
|
||||
$schema->allows('isManaged')->andReturn(true);
|
||||
$schema = SchemaFixture::managed();
|
||||
|
||||
self::assertTrue((new ContentTypesAbility($schema))->permission(['post_type' => 'page']));
|
||||
}
|
||||
|
||||
@@ -13,6 +13,8 @@ use LIT\MCP\Integrations\WordPress\Content\ContentUpdateAbility;
|
||||
use LIT\MCP\Integrations\WordPress\Content\PostPresenter;
|
||||
use LIT\MCP\Integrations\WordPress\Content\PostWriter;
|
||||
use LIT\MCP\Integrations\WordPress\Schema\ContentSchema;
|
||||
use LIT\MCP\Tests\Support\FakeChangeLog;
|
||||
use LIT\MCP\Tests\Support\SchemaFixture;
|
||||
use LIT\MCP\Tests\Unit\TestCase;
|
||||
use Mockery;
|
||||
use RuntimeException;
|
||||
@@ -39,15 +41,14 @@ final class ContentUpdateAbilityTest extends TestCase
|
||||
|
||||
private function schema(): ContentSchema
|
||||
{
|
||||
$schema = Mockery::mock(ContentSchema::class);
|
||||
$schema->allows('isManaged')->andReturn(true);
|
||||
$schema = SchemaFixture::managed();
|
||||
|
||||
return $schema;
|
||||
}
|
||||
|
||||
private function ability(PostWriter $writer, ?ChangeLog $log = null): ContentUpdateAbility
|
||||
{
|
||||
return new ContentUpdateAbility($this->schema(), $writer, $log ?? Mockery::mock(ChangeLog::class));
|
||||
return new ContentUpdateAbility($this->schema(), $writer, $log ?? FakeChangeLog::forbidden());
|
||||
}
|
||||
|
||||
public function testRevIsRequired(): void
|
||||
@@ -155,8 +156,7 @@ final class ContentUpdateAbilityTest extends TestCase
|
||||
Actions\expectDone('lit_mcp_after_save')->once()->with(5, 'lit/content-update', $input);
|
||||
Functions\when('get_preview_post_link')->justReturn('https://kunde.de/team/');
|
||||
Functions\when('get_edit_post_link')->justReturn('https://kunde.de/wp-admin/post.php?post=5&action=edit');
|
||||
$log = Mockery::mock(ChangeLog::class);
|
||||
$log->expects('record')->with('lit/content-update', 'page', '5', Mockery::type('string'), 811)->andReturn(4711);
|
||||
$log = new FakeChangeLog(4711);
|
||||
|
||||
$result = $this->ability($writer, $log)->execute($input);
|
||||
|
||||
@@ -166,6 +166,12 @@ final class ContentUpdateAbilityTest extends TestCase
|
||||
self::assertSame('updated', $result['changed'][0]['action']);
|
||||
self::assertSame(Rev::ofPost($this->post), $result['rev']);
|
||||
self::assertStringContainsString('Status unverändert: publish', $result['summary']);
|
||||
$log->assertRecorded([
|
||||
'ability' => 'lit/content-update',
|
||||
'object_type' => 'page',
|
||||
'object_id' => '5',
|
||||
'revision_id' => 811,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -197,8 +203,7 @@ final class ContentUpdateAbilityTest extends TestCase
|
||||
private function executeExpectingFailure(PostWriter $writer, array $input, ?ChangeLog $log = null): WriteFailed
|
||||
{
|
||||
if ($log === null) {
|
||||
$log = Mockery::mock(ChangeLog::class);
|
||||
$log->expects('record')->never();
|
||||
$log = FakeChangeLog::forbidden();
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -298,14 +303,14 @@ final class ContentUpdateAbilityTest extends TestCase
|
||||
});
|
||||
Functions\when('wp_revisions_enabled')->justReturn(true);
|
||||
Functions\expect('wp_restore_post_revision')->never();
|
||||
$log = Mockery::mock(ChangeLog::class);
|
||||
$log->expects('recordPartial');
|
||||
$log = FakeChangeLog::partialsOnly();
|
||||
|
||||
$failure = $this->executeExpectingFailure($writer, $input, $log);
|
||||
|
||||
self::assertFalse($failure->rolledBack);
|
||||
self::assertCount(1, $updates);
|
||||
self::assertStringContainsString('publish', $failure->getMessage());
|
||||
$log->assertPartials([]);
|
||||
}
|
||||
|
||||
public function testAnIncompleteRollbackIsAPartialWriteAndLogged(): void
|
||||
@@ -314,10 +319,7 @@ final class ContentUpdateAbilityTest extends TestCase
|
||||
$updates = [];
|
||||
$this->captureUpdates($updates);
|
||||
Functions\when('wp_revisions_enabled')->justReturn(false);
|
||||
$log = Mockery::mock(ChangeLog::class);
|
||||
$log->expects('recordPartial')
|
||||
->with('lit/content-update', 'page', '5', Mockery::type('string'), 811)
|
||||
->andReturn(12);
|
||||
$log = FakeChangeLog::partialsOnly();
|
||||
|
||||
$failure = $this->executeExpectingFailure($writer, $input, $log);
|
||||
|
||||
@@ -327,6 +329,12 @@ final class ContentUpdateAbilityTest extends TestCase
|
||||
self::assertSame('lit_partial_write', $error->get_error_code());
|
||||
self::assertSame(5, $error->get_error_data()['post_id']);
|
||||
self::assertSame(811, $error->get_error_data()['revision_id']);
|
||||
$log->assertPartials([
|
||||
'ability' => 'lit/content-update',
|
||||
'object_type' => 'page',
|
||||
'object_id' => '5',
|
||||
'revision_id' => 811,
|
||||
]);
|
||||
}
|
||||
|
||||
public function testFailuresAfterTheWriteOnlyAddWarnings(): void
|
||||
@@ -345,8 +353,7 @@ final class ContentUpdateAbilityTest extends TestCase
|
||||
Actions\expectDone('lit_mcp_after_save')->once()->whenHappen(static function (): void {
|
||||
throw new RuntimeException('listener kaputt');
|
||||
});
|
||||
$log = Mockery::mock(ChangeLog::class);
|
||||
$log->expects('record')->andThrow(new RuntimeException('db weg'));
|
||||
$log = new FakeChangeLog(1, new RuntimeException('db weg'));
|
||||
$file = (string) tempnam(sys_get_temp_dir(), 'lit-mcp-log');
|
||||
$previous = ini_set('error_log', $file);
|
||||
|
||||
@@ -361,5 +368,6 @@ final class ContentUpdateAbilityTest extends TestCase
|
||||
self::assertCount(2, $result['warnings']);
|
||||
self::assertStringContainsString('listener kaputt', (string) file_get_contents($file));
|
||||
unlink($file);
|
||||
$log->assertRecorded([]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,9 +6,9 @@ namespace LIT\MCP\Tests\Unit\Integrations\WordPress\Content;
|
||||
|
||||
use Brain\Monkey\Functions;
|
||||
use LIT\MCP\Abilities\WriteFailed;
|
||||
use LIT\MCP\ChangeLog\ChangeLog;
|
||||
use LIT\MCP\Integrations\WordPress\Content\NewDraft;
|
||||
use LIT\MCP\Integrations\WordPress\Content\PostWriter;
|
||||
use LIT\MCP\Tests\Support\FakeChangeLog;
|
||||
use LIT\MCP\Tests\Unit\TestCase;
|
||||
use Mockery;
|
||||
use RuntimeException;
|
||||
@@ -22,9 +22,7 @@ final class NewDraftTest extends TestCase
|
||||
Functions\when('wp_delete_post')->alias(static function (): never {
|
||||
throw new RuntimeException('delete_post hook kaputt');
|
||||
});
|
||||
$log = Mockery::mock(ChangeLog::class);
|
||||
$log->expects('recordPartial')
|
||||
->with('lit/content-create', 'page', '42', 'Entwurf 42: Anlegen nur teilweise zurückgenommen');
|
||||
$log = FakeChangeLog::partialsOnly();
|
||||
$draft = new NewDraft($writer, $log, 'lit/content-create', 'page');
|
||||
|
||||
try {
|
||||
@@ -40,6 +38,12 @@ final class NewDraftTest extends TestCase
|
||||
$e->getMessage()
|
||||
);
|
||||
}
|
||||
$log->assertPartials([
|
||||
'ability' => 'lit/content-create',
|
||||
'object_type' => 'page',
|
||||
'object_id' => '42',
|
||||
'summary' => 'Entwurf 42: Anlegen nur teilweise zurückgenommen',
|
||||
]);
|
||||
}
|
||||
|
||||
public function testACleanDiscardIsRolledBackWithTheGivenReason(): void
|
||||
@@ -47,8 +51,7 @@ final class NewDraftTest extends TestCase
|
||||
$writer = Mockery::mock(PostWriter::class);
|
||||
$writer->expects('deleteCreatedTerms');
|
||||
Functions\expect('wp_delete_post')->once()->with(42, true)->andReturn(true);
|
||||
$log = Mockery::mock(ChangeLog::class);
|
||||
$log->expects('recordPartial')->never();
|
||||
$log = FakeChangeLog::forbidden();
|
||||
$draft = new NewDraft($writer, $log, 'lit/content-create', 'page');
|
||||
|
||||
try {
|
||||
|
||||
@@ -5,10 +5,9 @@ declare(strict_types=1);
|
||||
namespace LIT\MCP\Tests\Unit\Integrations\WordPress\Menus;
|
||||
|
||||
use Brain\Monkey\Functions;
|
||||
use LIT\MCP\ChangeLog\ChangeLog;
|
||||
use LIT\MCP\Integrations\WordPress\Menus\MenuAssignLocationAbility;
|
||||
use LIT\MCP\Tests\Support\FakeChangeLog;
|
||||
use LIT\MCP\Tests\Unit\TestCase;
|
||||
use Mockery;
|
||||
|
||||
final class MenuAssignLocationAbilityTest extends TestCase
|
||||
{
|
||||
@@ -29,28 +28,26 @@ final class MenuAssignLocationAbilityTest extends TestCase
|
||||
public function testAssignsAndReportsThePreviousMenu(): void
|
||||
{
|
||||
Functions\expect('set_theme_mod')->once()->with('nav_menu_locations', ['primary-menu' => 8]);
|
||||
$log = Mockery::mock(ChangeLog::class);
|
||||
$log->expects('record')
|
||||
->with(
|
||||
'lit/menu-assign-location',
|
||||
'menu_location',
|
||||
'primary-menu',
|
||||
'Menü 8 der Position primary-menu zugewiesen'
|
||||
)
|
||||
->andReturn(6);
|
||||
$log = new FakeChangeLog(6);
|
||||
|
||||
$result = (new MenuAssignLocationAbility($log))->execute(['location' => 'primary-menu', 'menu_id' => 8]);
|
||||
|
||||
self::assertSame(3, $result['previous_menu_id']);
|
||||
self::assertSame('assigned', $result['changed'][0]['action']);
|
||||
self::assertSame(6, $result['log_id']);
|
||||
$log->assertRecorded([
|
||||
'ability' => 'lit/menu-assign-location',
|
||||
'object_type' => 'menu_location',
|
||||
'object_id' => 'primary-menu',
|
||||
'summary' => 'Menü 8 der Position primary-menu zugewiesen',
|
||||
]);
|
||||
}
|
||||
|
||||
public function testRemovingAnAssignmentNeedsConfirmation(): void
|
||||
{
|
||||
Functions\expect('set_theme_mod')->never();
|
||||
|
||||
$result = (new MenuAssignLocationAbility(Mockery::mock(ChangeLog::class)))
|
||||
$result = (new MenuAssignLocationAbility(FakeChangeLog::forbidden()))
|
||||
->execute(['location' => 'primary-menu', 'menu_id' => 0]);
|
||||
|
||||
self::assertSame('lit_confirm_required', $result->get_error_code());
|
||||
@@ -63,15 +60,7 @@ final class MenuAssignLocationAbilityTest extends TestCase
|
||||
public function testZeroRemovesTheAssignmentAndNamesTheRemovedMenu(): void
|
||||
{
|
||||
Functions\expect('set_theme_mod')->once()->with('nav_menu_locations', []);
|
||||
$log = Mockery::mock(ChangeLog::class);
|
||||
$log->expects('record')
|
||||
->with(
|
||||
'lit/menu-assign-location',
|
||||
'menu_location',
|
||||
'primary-menu',
|
||||
'Menü "Hauptmenü" (ID 3) von der Position primary-menu entfernt'
|
||||
)
|
||||
->andReturn(7);
|
||||
$log = new FakeChangeLog(7);
|
||||
|
||||
$result = (new MenuAssignLocationAbility($log))
|
||||
->execute(['location' => 'primary-menu', 'menu_id' => 0, 'confirm' => true]);
|
||||
@@ -80,14 +69,19 @@ final class MenuAssignLocationAbilityTest extends TestCase
|
||||
self::assertSame(3, $result['previous_menu_id']);
|
||||
self::assertStringContainsString('"Hauptmenü" (ID 3)', $result['summary']);
|
||||
self::assertSame(7, $result['log_id']);
|
||||
$log->assertRecorded([
|
||||
'ability' => 'lit/menu-assign-location',
|
||||
'object_type' => 'menu_location',
|
||||
'object_id' => 'primary-menu',
|
||||
'summary' => 'Menü "Hauptmenü" (ID 3) von der Position primary-menu entfernt',
|
||||
]);
|
||||
}
|
||||
|
||||
public function testRemovingFromAnEmptyLocationNeedsNoConfirmation(): void
|
||||
{
|
||||
Functions\when('get_nav_menu_locations')->justReturn([]);
|
||||
Functions\expect('set_theme_mod')->once()->with('nav_menu_locations', []);
|
||||
$log = Mockery::mock(ChangeLog::class);
|
||||
$log->allows('record')->andReturn(8);
|
||||
$log = new FakeChangeLog(8);
|
||||
|
||||
$result = (new MenuAssignLocationAbility($log))->execute(['location' => 'primary-menu', 'menu_id' => 0]);
|
||||
|
||||
@@ -97,7 +91,7 @@ final class MenuAssignLocationAbilityTest extends TestCase
|
||||
|
||||
public function testDescribesTheConfirmationForRemoval(): void
|
||||
{
|
||||
$ability = new MenuAssignLocationAbility(Mockery::mock(ChangeLog::class));
|
||||
$ability = new MenuAssignLocationAbility(FakeChangeLog::forbidden());
|
||||
|
||||
self::assertArrayHasKey('confirm', $ability->inputSchema()['properties']);
|
||||
self::assertStringContainsString('confirm: true', $ability->description());
|
||||
@@ -107,7 +101,7 @@ final class MenuAssignLocationAbilityTest extends TestCase
|
||||
{
|
||||
Functions\expect('set_theme_mod')->never();
|
||||
|
||||
$result = (new MenuAssignLocationAbility(Mockery::mock(ChangeLog::class)))
|
||||
$result = (new MenuAssignLocationAbility(FakeChangeLog::forbidden()))
|
||||
->execute(['location' => 'primary-menu', 'menu_id' => 99]);
|
||||
|
||||
self::assertSame('lit_not_found', $result->get_error_code());
|
||||
@@ -117,7 +111,7 @@ final class MenuAssignLocationAbilityTest extends TestCase
|
||||
{
|
||||
Functions\when('current_user_can')->justReturn(false);
|
||||
|
||||
$ability = new MenuAssignLocationAbility(Mockery::mock(ChangeLog::class));
|
||||
$ability = new MenuAssignLocationAbility(FakeChangeLog::forbidden());
|
||||
$input = ['location' => 'primary-menu', 'menu_id' => 8];
|
||||
|
||||
self::assertSame('lit_forbidden', $ability->permission($input)->get_error_code());
|
||||
@@ -125,7 +119,7 @@ final class MenuAssignLocationAbilityTest extends TestCase
|
||||
|
||||
public function testIsDestructiveBecauseItReplacesTheMenuOfTheLocation(): void
|
||||
{
|
||||
$ability = new MenuAssignLocationAbility(Mockery::mock(ChangeLog::class));
|
||||
$ability = new MenuAssignLocationAbility(FakeChangeLog::forbidden());
|
||||
|
||||
self::assertSame(['readonly' => false, 'destructive' => true, 'idempotent' => true], $ability->annotations());
|
||||
}
|
||||
|
||||
@@ -5,10 +5,9 @@ declare(strict_types=1);
|
||||
namespace LIT\MCP\Tests\Unit\Integrations\WordPress\Menus;
|
||||
|
||||
use Brain\Monkey\Functions;
|
||||
use LIT\MCP\ChangeLog\ChangeLog;
|
||||
use LIT\MCP\Integrations\WordPress\Menus\MenuCreateAbility;
|
||||
use LIT\MCP\Tests\Support\FakeChangeLog;
|
||||
use LIT\MCP\Tests\Unit\TestCase;
|
||||
use Mockery;
|
||||
use WP_Error;
|
||||
|
||||
final class MenuCreateAbilityTest extends TestCase
|
||||
@@ -18,7 +17,7 @@ final class MenuCreateAbilityTest extends TestCase
|
||||
Functions\when('get_registered_nav_menus')->justReturn(['primary-menu' => 'Hauptmenü']);
|
||||
Functions\expect('wp_create_nav_menu')->never();
|
||||
|
||||
$ability = new MenuCreateAbility(Mockery::mock(ChangeLog::class));
|
||||
$ability = new MenuCreateAbility(FakeChangeLog::forbidden());
|
||||
$result = $ability->execute(['name' => 'Neu', 'location' => 'nope']);
|
||||
|
||||
self::assertSame('lit_validation_failed', $result->get_error_code());
|
||||
@@ -31,7 +30,7 @@ final class MenuCreateAbilityTest extends TestCase
|
||||
new WP_Error('menu_exists', 'Der Menüname existiert bereits.')
|
||||
);
|
||||
|
||||
$result = (new MenuCreateAbility(Mockery::mock(ChangeLog::class)))->execute(['name' => 'Hauptmenü']);
|
||||
$result = (new MenuCreateAbility(FakeChangeLog::forbidden()))->execute(['name' => 'Hauptmenü']);
|
||||
|
||||
self::assertSame('lit_validation_failed', $result->get_error_code());
|
||||
}
|
||||
@@ -45,23 +44,26 @@ final class MenuCreateAbilityTest extends TestCase
|
||||
'nav_menu_locations',
|
||||
['footer-menu' => 2, 'primary-menu' => 8]
|
||||
);
|
||||
$log = Mockery::mock(ChangeLog::class);
|
||||
$log->expects('record')
|
||||
->with('lit/menu-create', 'nav_menu', '8', 'Menü "Neu" angelegt (Position primary-menu)')
|
||||
->andReturn(5);
|
||||
$log = new FakeChangeLog(5);
|
||||
|
||||
$result = (new MenuCreateAbility($log))->execute(['name' => 'Neu', 'location' => 'primary-menu']);
|
||||
|
||||
self::assertSame(8, $result['menu_id']);
|
||||
self::assertSame('created', $result['changed'][0]['action']);
|
||||
self::assertSame(5, $result['log_id']);
|
||||
$log->assertRecorded([
|
||||
'ability' => 'lit/menu-create',
|
||||
'object_type' => 'nav_menu',
|
||||
'object_id' => '8',
|
||||
'summary' => 'Menü "Neu" angelegt (Position primary-menu)',
|
||||
]);
|
||||
}
|
||||
|
||||
public function testPermissionNeedsThemeOptionRights(): void
|
||||
{
|
||||
Functions\when('current_user_can')->justReturn(false);
|
||||
|
||||
$ability = new MenuCreateAbility(Mockery::mock(ChangeLog::class));
|
||||
$ability = new MenuCreateAbility(FakeChangeLog::forbidden());
|
||||
|
||||
self::assertSame('lit_forbidden', $ability->permission(['name' => 'Neu'])->get_error_code());
|
||||
}
|
||||
|
||||
@@ -7,11 +7,11 @@ namespace LIT\MCP\Tests\Unit\Integrations\WordPress\Menus;
|
||||
use Brain\Monkey\Functions;
|
||||
use LIT\MCP\Abilities\Rev;
|
||||
use LIT\MCP\Abilities\WriteFailed;
|
||||
use LIT\MCP\ChangeLog\ChangeLog;
|
||||
use LIT\MCP\Integrations\WordPress\Menus\MenuOperations;
|
||||
use LIT\MCP\Integrations\WordPress\Menus\MenuSetItemsAbility;
|
||||
use LIT\MCP\Integrations\WordPress\Menus\MenuTree;
|
||||
use LIT\MCP\Integrations\WordPress\Menus\MenuWriter;
|
||||
use LIT\MCP\Tests\Support\FakeChangeLog;
|
||||
use LIT\MCP\Tests\Unit\TestCase;
|
||||
use Mockery;
|
||||
use RuntimeException;
|
||||
@@ -37,7 +37,7 @@ final class MenuSetItemsAbilityTest extends TestCase
|
||||
{
|
||||
$writer = Mockery::mock(MenuWriter::class);
|
||||
$writer->expects('apply')->never();
|
||||
$ability = new MenuSetItemsAbility($writer, new MenuOperations(), Mockery::mock(ChangeLog::class));
|
||||
$ability = new MenuSetItemsAbility($writer, new MenuOperations(), FakeChangeLog::forbidden());
|
||||
|
||||
$stale = $ability->execute(['menu_id' => 3, 'menu_rev' => 'abcdefabcdef', 'items' => [['id' => 10]]]);
|
||||
$missing = $ability->execute(['menu_id' => 3, 'items' => [['id' => 10]]]);
|
||||
@@ -55,8 +55,7 @@ final class MenuSetItemsAbilityTest extends TestCase
|
||||
$writer = Mockery::mock(MenuWriter::class);
|
||||
$writer->allows('plan')->andReturn(['errors' => [], 'removals' => [], 'warnings' => []]);
|
||||
$writer->allows('apply')->andReturn(['created' => 0, 'updated' => 1, 'removed' => 0]);
|
||||
$log = Mockery::mock(ChangeLog::class);
|
||||
$log->allows('record')->andReturn(30);
|
||||
$log = new FakeChangeLog(30);
|
||||
|
||||
$result = (new MenuSetItemsAbility($writer, new MenuOperations(), $log))->execute(
|
||||
['menu_id' => 3, 'menu_rev' => self::rev(), 'items' => [['id' => 10]]]
|
||||
@@ -67,7 +66,7 @@ final class MenuSetItemsAbilityTest extends TestCase
|
||||
|
||||
public function testItemsAndOperationsAreMutuallyExclusive(): void
|
||||
{
|
||||
$ability = new MenuSetItemsAbility(new MenuWriter(), new MenuOperations(), Mockery::mock(ChangeLog::class));
|
||||
$ability = new MenuSetItemsAbility(new MenuWriter(), new MenuOperations(), FakeChangeLog::forbidden());
|
||||
|
||||
self::assertSame('lit_validation_failed', $ability->execute(['menu_id' => 3, 'menu_rev' => self::rev()])->get_error_code());
|
||||
self::assertSame(
|
||||
@@ -80,7 +79,7 @@ final class MenuSetItemsAbilityTest extends TestCase
|
||||
public function testUnknownMenuIsNotFound(): void
|
||||
{
|
||||
Functions\when('wp_get_nav_menu_object')->justReturn(false);
|
||||
$ability = new MenuSetItemsAbility(new MenuWriter(), new MenuOperations(), Mockery::mock(ChangeLog::class));
|
||||
$ability = new MenuSetItemsAbility(new MenuWriter(), new MenuOperations(), FakeChangeLog::forbidden());
|
||||
|
||||
self::assertSame('lit_not_found', $ability->execute(['menu_id' => 9, 'items' => []])->get_error_code());
|
||||
}
|
||||
@@ -89,7 +88,7 @@ final class MenuSetItemsAbilityTest extends TestCase
|
||||
{
|
||||
Functions\expect('wp_update_nav_menu_item')->never();
|
||||
Functions\expect('wp_delete_post')->never();
|
||||
$ability = new MenuSetItemsAbility(new MenuWriter(), new MenuOperations(), Mockery::mock(ChangeLog::class));
|
||||
$ability = new MenuSetItemsAbility(new MenuWriter(), new MenuOperations(), FakeChangeLog::forbidden());
|
||||
|
||||
$result = $ability->execute(['menu_id' => 3, 'menu_rev' => self::rev(), 'items' => []]);
|
||||
|
||||
@@ -102,7 +101,7 @@ final class MenuSetItemsAbilityTest extends TestCase
|
||||
Functions\when('wp_parse_url')->alias('parse_url');
|
||||
Functions\expect('wp_update_nav_menu_item')->never();
|
||||
Functions\expect('wp_delete_post')->never();
|
||||
$ability = new MenuSetItemsAbility(new MenuWriter(), new MenuOperations(), Mockery::mock(ChangeLog::class));
|
||||
$ability = new MenuSetItemsAbility(new MenuWriter(), new MenuOperations(), FakeChangeLog::forbidden());
|
||||
|
||||
$result = $ability->execute([
|
||||
'menu_id' => 3, 'menu_rev' => self::rev(),
|
||||
@@ -118,7 +117,7 @@ final class MenuSetItemsAbilityTest extends TestCase
|
||||
{
|
||||
$writer = Mockery::mock(MenuWriter::class);
|
||||
$writer->expects('apply')->never();
|
||||
$ability = new MenuSetItemsAbility($writer, new MenuOperations(), Mockery::mock(ChangeLog::class));
|
||||
$ability = new MenuSetItemsAbility($writer, new MenuOperations(), FakeChangeLog::forbidden());
|
||||
|
||||
$result = $ability->execute(['menu_id' => 3, 'menu_rev' => self::rev(), 'operations' => [['op' => 'move', 'id' => 99]]]);
|
||||
|
||||
@@ -130,8 +129,7 @@ final class MenuSetItemsAbilityTest extends TestCase
|
||||
$writer = Mockery::mock(MenuWriter::class);
|
||||
$writer->allows('plan')->andReturn(['errors' => [], 'removals' => [], 'warnings' => []]);
|
||||
$writer->expects('apply')->andReturn(['created' => 1, 'updated' => 1, 'removed' => 0]);
|
||||
$log = Mockery::mock(ChangeLog::class);
|
||||
$log->expects('record')->with('lit/menu-set-items', 'nav_menu', '3', Mockery::type('string'))->andReturn(21);
|
||||
$log = new FakeChangeLog(21);
|
||||
|
||||
$result = (new MenuSetItemsAbility($writer, new MenuOperations(), $log))->execute([
|
||||
'menu_id' => 3, 'menu_rev' => self::rev(),
|
||||
@@ -141,6 +139,7 @@ final class MenuSetItemsAbilityTest extends TestCase
|
||||
self::assertSame('Home', $result['previous_items'][0]['title']);
|
||||
self::assertSame(21, $result['log_id']);
|
||||
self::assertStringContainsString('1 neu, 1 geändert, 0 entfernt', $result['summary']);
|
||||
$log->assertRecorded(['ability' => 'lit/menu-set-items', 'object_type' => 'nav_menu', 'object_id' => '3']);
|
||||
}
|
||||
|
||||
public function testConfirmedRemovalsAreWrittenAndTheOldTreeIsReturned(): void
|
||||
@@ -151,8 +150,7 @@ final class MenuSetItemsAbilityTest extends TestCase
|
||||
);
|
||||
$writer->expects('apply')->with(3, [], Mockery::type('array'))
|
||||
->andReturn(['created' => 0, 'updated' => 0, 'removed' => 1]);
|
||||
$log = Mockery::mock(ChangeLog::class);
|
||||
$log->allows('record')->andReturn(22);
|
||||
$log = new FakeChangeLog(22);
|
||||
|
||||
$result = (new MenuSetItemsAbility($writer, new MenuOperations(), $log))->execute(
|
||||
['menu_id' => 3, 'menu_rev' => self::rev(), 'items' => [], 'confirm' => true]
|
||||
@@ -169,8 +167,7 @@ final class MenuSetItemsAbilityTest extends TestCase
|
||||
Functions\when('wp_get_nav_menu_items')->justReturn($items);
|
||||
Functions\expect('wp_delete_post')->never();
|
||||
Functions\expect('wp_update_nav_menu_item')->never();
|
||||
$log = Mockery::mock(ChangeLog::class);
|
||||
$log->expects('record')->never();
|
||||
$log = FakeChangeLog::forbidden();
|
||||
|
||||
$result = (new MenuSetItemsAbility(new MenuWriter(), new MenuOperations(), $log))->execute(
|
||||
['menu_id' => 3, 'menu_rev' => self::rev(), 'items' => MenuTree::build($items)]
|
||||
@@ -187,7 +184,7 @@ final class MenuSetItemsAbilityTest extends TestCase
|
||||
$writer = Mockery::mock(MenuWriter::class);
|
||||
$writer->expects('plan')->with(Mockery::type('array'), Mockery::type('array'), true)
|
||||
->andReturn(['errors' => ['items.0' => 'x'], 'removals' => [], 'warnings' => []]);
|
||||
$ability = new MenuSetItemsAbility($writer, new MenuOperations(), Mockery::mock(ChangeLog::class));
|
||||
$ability = new MenuSetItemsAbility($writer, new MenuOperations(), FakeChangeLog::forbidden());
|
||||
|
||||
$result = $ability->execute(
|
||||
['menu_id' => 3, 'menu_rev' => self::rev(), 'items' => [['type' => 'post', 'object_id' => 7]], 'allow_unpublished' => true]
|
||||
@@ -205,8 +202,7 @@ final class MenuSetItemsAbilityTest extends TestCase
|
||||
);
|
||||
Functions\when('get_post_type')->justReturn('page');
|
||||
Functions\expect('wp_update_nav_menu_item')->once()->andReturn(60);
|
||||
$log = Mockery::mock(ChangeLog::class);
|
||||
$log->allows('record')->andReturn(24);
|
||||
$log = new FakeChangeLog(24);
|
||||
$ability = new MenuSetItemsAbility(new MenuWriter(), new MenuOperations(), $log);
|
||||
$input = ['menu_id' => 3, 'menu_rev' => self::rev(), 'operations' => [['op' => 'add', 'item' => ['type' => 'post', 'object_id' => 7]]]];
|
||||
|
||||
@@ -226,7 +222,7 @@ final class MenuSetItemsAbilityTest extends TestCase
|
||||
new \WP_Post(['ID' => 7, 'post_type' => 'page', 'post_status' => 'private', 'post_title' => 'Intern'])
|
||||
);
|
||||
Functions\expect('wp_update_nav_menu_item')->never();
|
||||
$ability = new MenuSetItemsAbility(new MenuWriter(), new MenuOperations(), Mockery::mock(ChangeLog::class));
|
||||
$ability = new MenuSetItemsAbility(new MenuWriter(), new MenuOperations(), FakeChangeLog::forbidden());
|
||||
|
||||
$result = $ability->execute([
|
||||
'menu_id' => 3, 'menu_rev' => self::rev(),
|
||||
@@ -243,8 +239,7 @@ final class MenuSetItemsAbilityTest extends TestCase
|
||||
$writer = Mockery::mock(MenuWriter::class);
|
||||
$writer->allows('plan')->andReturn(['errors' => [], 'removals' => [], 'warnings' => []]);
|
||||
$writer->expects('apply')->andThrow(WriteFailed::rolledBack('Menü nicht gespeichert.'));
|
||||
$log = Mockery::mock(ChangeLog::class);
|
||||
$log->shouldNotReceive('recordPartial');
|
||||
$log = FakeChangeLog::forbidden();
|
||||
$ability = new MenuSetItemsAbility($writer, new MenuOperations(), $log);
|
||||
|
||||
$this->expectException(WriteFailed::class);
|
||||
@@ -256,12 +251,16 @@ final class MenuSetItemsAbilityTest extends TestCase
|
||||
$writer = Mockery::mock(MenuWriter::class);
|
||||
$writer->allows('plan')->andReturn(['errors' => [], 'removals' => [], 'warnings' => []]);
|
||||
$writer->expects('apply')->andThrow(WriteFailed::partial('Menü nicht gespeichert.'));
|
||||
$log = Mockery::mock(ChangeLog::class);
|
||||
$log->expects('recordPartial')->with('lit/menu-set-items', 'nav_menu', '3', Mockery::type('string'));
|
||||
$log = FakeChangeLog::partialsOnly();
|
||||
$ability = new MenuSetItemsAbility($writer, new MenuOperations(), $log);
|
||||
|
||||
$this->expectException(WriteFailed::class);
|
||||
$ability->execute(['menu_id' => 3, 'menu_rev' => self::rev(), 'items' => [['id' => 10]]]);
|
||||
try {
|
||||
$ability->execute(['menu_id' => 3, 'menu_rev' => self::rev(), 'items' => [['id' => 10]]]);
|
||||
self::fail('WriteFailed expected');
|
||||
} catch (WriteFailed $e) {
|
||||
self::assertFalse($e->rolledBack);
|
||||
}
|
||||
$log->assertPartials(['ability' => 'lit/menu-set-items', 'object_type' => 'nav_menu', 'object_id' => '3']);
|
||||
}
|
||||
|
||||
public function testAChangeLogFailureIsOnlyAWarning(): void
|
||||
@@ -269,8 +268,7 @@ final class MenuSetItemsAbilityTest extends TestCase
|
||||
$writer = Mockery::mock(MenuWriter::class);
|
||||
$writer->allows('plan')->andReturn(['errors' => [], 'removals' => [], 'warnings' => ['"X" ist nicht veröffentlicht']]);
|
||||
$writer->allows('apply')->andReturn(['created' => 0, 'updated' => 1, 'removed' => 0]);
|
||||
$log = Mockery::mock(ChangeLog::class);
|
||||
$log->allows('record')->andThrow(new RuntimeException('db down'));
|
||||
$log = new FakeChangeLog(1, new RuntimeException('db down'));
|
||||
$file = (string) tempnam(sys_get_temp_dir(), 'lit');
|
||||
$errorLog = ini_set('error_log', $file);
|
||||
|
||||
@@ -290,14 +288,14 @@ final class MenuSetItemsAbilityTest extends TestCase
|
||||
public function testPermissionNeedsThemeOptionRights(): void
|
||||
{
|
||||
Functions\when('current_user_can')->justReturn(false);
|
||||
$ability = new MenuSetItemsAbility(new MenuWriter(), new MenuOperations(), Mockery::mock(ChangeLog::class));
|
||||
$ability = new MenuSetItemsAbility(new MenuWriter(), new MenuOperations(), FakeChangeLog::forbidden());
|
||||
|
||||
self::assertSame('lit_forbidden', $ability->permission(['menu_id' => 3, 'menu_rev' => self::rev()])->get_error_code());
|
||||
}
|
||||
|
||||
public function testIsDestructiveAndDescribesWhenConfirmIsNeeded(): void
|
||||
{
|
||||
$ability = new MenuSetItemsAbility(new MenuWriter(), new MenuOperations(), Mockery::mock(ChangeLog::class));
|
||||
$ability = new MenuSetItemsAbility(new MenuWriter(), new MenuOperations(), FakeChangeLog::forbidden());
|
||||
|
||||
self::assertSame(['readonly' => false, 'destructive' => true, 'idempotent' => false], $ability->annotations());
|
||||
self::assertStringContainsString('confirm: true', $ability->description());
|
||||
|
||||
@@ -7,10 +7,9 @@ namespace LIT\MCP\Tests\Unit\Integrations\WordPress;
|
||||
use Brain\Monkey\Actions;
|
||||
use Brain\Monkey\Functions;
|
||||
use LIT\MCP\Abilities\Rev;
|
||||
use LIT\MCP\ChangeLog\ChangeLog;
|
||||
use LIT\MCP\Integrations\WordPress\PostChangeResult;
|
||||
use LIT\MCP\Tests\Support\FakeChangeLog;
|
||||
use LIT\MCP\Tests\Unit\TestCase;
|
||||
use Mockery;
|
||||
use RuntimeException;
|
||||
use WP_Post;
|
||||
|
||||
@@ -38,8 +37,7 @@ final class PostChangeResultTest extends TestCase
|
||||
$post = new WP_Post(['ID' => 5, 'post_title' => 'Team']);
|
||||
Actions\expectDone('lit_mcp_after_save')->once()->with(5, 'lit/content-update', ['post_id' => 5]);
|
||||
Functions\when('get_post')->justReturn($post);
|
||||
$log = Mockery::mock(ChangeLog::class);
|
||||
$log->expects('record')->with('lit/content-update', 'page', '5', 'geändert', 811)->andReturn(9);
|
||||
$log = new FakeChangeLog(9);
|
||||
|
||||
$change = new PostChangeResult('lit/content-update', $log, 5, 'die Änderung', ['vorher']);
|
||||
$change->afterSave(['post_id' => 5]);
|
||||
@@ -52,6 +50,13 @@ final class PostChangeResultTest extends TestCase
|
||||
self::assertSame(Rev::ofPost($post), $result['rev']);
|
||||
self::assertSame(9, $result['log_id']);
|
||||
self::assertSame(['vorher'], $result['warnings']);
|
||||
$log->assertRecorded([
|
||||
'ability' => 'lit/content-update',
|
||||
'object_type' => 'page',
|
||||
'object_id' => '5',
|
||||
'summary' => 'geändert',
|
||||
'revision_id' => 811,
|
||||
]);
|
||||
}
|
||||
|
||||
public function testFailuresAfterTheWriteBecomeWarnings(): void
|
||||
@@ -60,8 +65,7 @@ final class PostChangeResultTest extends TestCase
|
||||
throw new RuntimeException('listener kaputt');
|
||||
});
|
||||
Functions\when('get_post')->justReturn(null);
|
||||
$log = Mockery::mock(ChangeLog::class);
|
||||
$log->expects('record')->andThrow(new RuntimeException('log kaputt'));
|
||||
$log = new FakeChangeLog(1, new RuntimeException('log kaputt'));
|
||||
$fallback = new WP_Post(['ID' => 5]);
|
||||
|
||||
$change = new PostChangeResult('lit/post-publish', $log, 5);
|
||||
@@ -77,13 +81,14 @@ final class PostChangeResultTest extends TestCase
|
||||
'Änderungsprotokoll konnte nicht geschrieben werden; die Änderung ist gespeichert.',
|
||||
], $result['warnings']);
|
||||
self::assertStringContainsString('listener kaputt', (string) file_get_contents($this->errorLog));
|
||||
$log->assertRecorded([]);
|
||||
}
|
||||
|
||||
public function testWithoutAReadablePostTheRevIsNull(): void
|
||||
{
|
||||
Functions\when('get_post')->justReturn(null);
|
||||
|
||||
$change = new PostChangeResult('lit/content-create', Mockery::mock(ChangeLog::class), 5, 'der Entwurf');
|
||||
$change = new PostChangeResult('lit/content-create', FakeChangeLog::forbidden(), 5, 'der Entwurf');
|
||||
|
||||
self::assertNull($change->reread());
|
||||
self::assertNull($change->result('ok', null)->toArray()['rev']);
|
||||
|
||||
@@ -8,7 +8,7 @@ use Brain\Monkey\Functions;
|
||||
use LIT\MCP\Integrations\WordPress\Render\PageRenderer;
|
||||
use LIT\MCP\Integrations\WordPress\Render\PageRenderSummaryAbility;
|
||||
use LIT\MCP\Integrations\WordPress\Render\RenderSummary;
|
||||
use LIT\MCP\Integrations\WordPress\Schema\ContentSchema;
|
||||
use LIT\MCP\Tests\Support\SchemaFixture;
|
||||
use LIT\MCP\Tests\Unit\TestCase;
|
||||
use Mockery;
|
||||
use WP_Post;
|
||||
@@ -123,8 +123,7 @@ final class PageRenderSummaryAbilityTest extends TestCase
|
||||
Functions\when('get_post')->justReturn($post);
|
||||
Functions\when('current_user_can')->justReturn(true);
|
||||
Functions\when('get_permalink')->justReturn('https://k.test/start/');
|
||||
$schema = Mockery::mock(ContentSchema::class);
|
||||
$schema->allows('isManaged')->andReturn(true);
|
||||
$schema = SchemaFixture::managed();
|
||||
$renderer = Mockery::mock(PageRenderer::class);
|
||||
$renderer->expects('render')->with($post)->andReturn(self::HTML);
|
||||
$ability = new PageRenderSummaryAbility($schema, $renderer);
|
||||
|
||||
@@ -9,9 +9,9 @@ use Brain\Monkey\Functions;
|
||||
use LIT\MCP\Abilities\Rev;
|
||||
use LIT\MCP\ChangeLog\ChangeLog;
|
||||
use LIT\MCP\Integrations\WordPress\Revisions\RevisionRestoreAbility;
|
||||
use LIT\MCP\Integrations\WordPress\Schema\ContentSchema;
|
||||
use LIT\MCP\Tests\Support\FakeChangeLog;
|
||||
use LIT\MCP\Tests\Support\SchemaFixture;
|
||||
use LIT\MCP\Tests\Unit\TestCase;
|
||||
use Mockery;
|
||||
use RuntimeException;
|
||||
use WP_Post;
|
||||
|
||||
@@ -38,8 +38,7 @@ final class RevisionRestoreAbilityTest extends TestCase
|
||||
|
||||
private function ability(ChangeLog $log): RevisionRestoreAbility
|
||||
{
|
||||
$schema = Mockery::mock(ContentSchema::class);
|
||||
$schema->allows('isManaged')->andReturn(true);
|
||||
$schema = SchemaFixture::managed();
|
||||
|
||||
return new RevisionRestoreAbility($schema, $log);
|
||||
}
|
||||
@@ -51,14 +50,14 @@ final class RevisionRestoreAbilityTest extends TestCase
|
||||
|
||||
public function testNonRevisionIdIsNotFound(): void
|
||||
{
|
||||
self::assertSame('lit_not_found', $this->ability(Mockery::mock(ChangeLog::class))->permission(['revision_id' => 5])->get_error_code());
|
||||
self::assertSame('lit_not_found', $this->ability(FakeChangeLog::forbidden())->permission(['revision_id' => 5])->get_error_code());
|
||||
}
|
||||
|
||||
public function testRequiresConfirmation(): void
|
||||
{
|
||||
Functions\expect('wp_restore_post_revision')->never();
|
||||
|
||||
$result = $this->ability(Mockery::mock(ChangeLog::class))->execute(['revision_id' => 810]);
|
||||
$result = $this->ability(FakeChangeLog::forbidden())->execute(['revision_id' => 810]);
|
||||
|
||||
self::assertSame('lit_confirm_required', $result->get_error_code());
|
||||
}
|
||||
@@ -69,7 +68,7 @@ final class RevisionRestoreAbilityTest extends TestCase
|
||||
? new WP_Post(['ID' => 810, 'post_type' => 'revision', 'post_parent' => 0])
|
||||
: null);
|
||||
|
||||
$error = $this->ability(Mockery::mock(ChangeLog::class))
|
||||
$error = $this->ability(FakeChangeLog::forbidden())
|
||||
->permission(['revision_id' => 810, 'rev' => 'irrelevant', 'confirm' => true]);
|
||||
|
||||
self::assertSame('lit_validation_failed', $error->get_error_code());
|
||||
@@ -85,7 +84,7 @@ final class RevisionRestoreAbilityTest extends TestCase
|
||||
});
|
||||
Functions\expect('wp_restore_post_revision')->never();
|
||||
|
||||
$error = $this->ability(Mockery::mock(ChangeLog::class))->execute(['revision_id' => 810, 'rev' => 'x', 'confirm' => true]);
|
||||
$error = $this->ability(FakeChangeLog::forbidden())->execute(['revision_id' => 810, 'rev' => 'x', 'confirm' => true]);
|
||||
|
||||
self::assertSame('lit_validation_failed', $error->get_error_code());
|
||||
self::assertArrayHasKey('revision_id', $error->get_error_data()['fields']);
|
||||
@@ -105,7 +104,7 @@ final class RevisionRestoreAbilityTest extends TestCase
|
||||
Functions\expect('wp_save_post_revision')->never();
|
||||
Functions\expect('wp_restore_post_revision')->never();
|
||||
|
||||
$error = $this->ability(Mockery::mock(ChangeLog::class))->execute([
|
||||
$error = $this->ability(FakeChangeLog::forbidden())->execute([
|
||||
'revision_id' => 810,
|
||||
'rev' => Rev::ofPost(new WP_Post($current)),
|
||||
'confirm' => true,
|
||||
@@ -119,7 +118,7 @@ final class RevisionRestoreAbilityTest extends TestCase
|
||||
{
|
||||
Functions\expect('wp_restore_post_revision')->never();
|
||||
|
||||
$result = $this->ability(Mockery::mock(ChangeLog::class))
|
||||
$result = $this->ability(FakeChangeLog::forbidden())
|
||||
->execute(['revision_id' => 810, 'confirm' => true, 'rev' => 'stale']);
|
||||
|
||||
self::assertSame('lit_rev_mismatch', $result->get_error_code());
|
||||
@@ -139,8 +138,7 @@ final class RevisionRestoreAbilityTest extends TestCase
|
||||
});
|
||||
Functions\when('get_preview_post_link')->justReturn('https://kunde.de/team/');
|
||||
Functions\when('get_edit_post_link')->justReturn('https://kunde.de/wp-admin/post.php?post=5&action=edit');
|
||||
$log = Mockery::mock(ChangeLog::class);
|
||||
$log->expects('record')->with('lit/revision-restore', 'page', '5', Mockery::type('string'), 813)->andReturn(12);
|
||||
$log = new FakeChangeLog(12);
|
||||
|
||||
$result = $this->ability($log)->execute([
|
||||
'revision_id' => 810,
|
||||
@@ -154,6 +152,12 @@ final class RevisionRestoreAbilityTest extends TestCase
|
||||
self::assertStringContainsString('2026-09-20 10:00:00', $result['summary']);
|
||||
self::assertStringContainsString('Status unverändert: publish', $result['summary']);
|
||||
self::assertSame([], $result['warnings']);
|
||||
$log->assertRecorded([
|
||||
'ability' => 'lit/revision-restore',
|
||||
'object_type' => 'page',
|
||||
'object_id' => '5',
|
||||
'revision_id' => 813,
|
||||
]);
|
||||
}
|
||||
|
||||
public function testRestoreFailureIsWriteFailed(): void
|
||||
@@ -161,8 +165,7 @@ final class RevisionRestoreAbilityTest extends TestCase
|
||||
Functions\when('wp_save_post_revision')->justReturn(813);
|
||||
Functions\when('wp_get_post_revisions')->justReturn([813 => new WP_Post(['ID' => 813])]);
|
||||
Functions\when('wp_restore_post_revision')->justReturn(false);
|
||||
$log = Mockery::mock(ChangeLog::class);
|
||||
$log->expects('record')->never();
|
||||
$log = FakeChangeLog::forbidden();
|
||||
|
||||
$result = $this->ability($log)->execute([
|
||||
'revision_id' => 810,
|
||||
@@ -188,8 +191,7 @@ final class RevisionRestoreAbilityTest extends TestCase
|
||||
Actions\expectDone('lit_mcp_after_save')->once()->whenHappen(static function (): void {
|
||||
throw new RuntimeException('listener kaputt');
|
||||
});
|
||||
$log = Mockery::mock(ChangeLog::class);
|
||||
$log->expects('record')->andThrow(new RuntimeException('db weg'));
|
||||
$log = new FakeChangeLog(1, new RuntimeException('db weg'));
|
||||
$file = (string) tempnam(sys_get_temp_dir(), 'lit-mcp-log');
|
||||
$previous = ini_set('error_log', $file);
|
||||
|
||||
@@ -208,5 +210,6 @@ final class RevisionRestoreAbilityTest extends TestCase
|
||||
self::assertCount(2, $result['warnings']);
|
||||
self::assertStringContainsString('listener kaputt', (string) file_get_contents($file));
|
||||
unlink($file);
|
||||
$log->assertRecorded([]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,9 +8,8 @@ use Brain\Monkey\Functions;
|
||||
use LIT\MCP\Abilities\Cursor;
|
||||
use LIT\MCP\Integrations\WordPress\Content\PostPresenter;
|
||||
use LIT\MCP\Integrations\WordPress\Revisions\RevisionsListAbility;
|
||||
use LIT\MCP\Integrations\WordPress\Schema\ContentSchema;
|
||||
use LIT\MCP\Tests\Support\SchemaFixture;
|
||||
use LIT\MCP\Tests\Unit\TestCase;
|
||||
use Mockery;
|
||||
use WP_Post;
|
||||
|
||||
final class RevisionsListAbilityTest extends TestCase
|
||||
@@ -27,8 +26,7 @@ final class RevisionsListAbilityTest extends TestCase
|
||||
|
||||
private function ability(): RevisionsListAbility
|
||||
{
|
||||
$schema = Mockery::mock(ContentSchema::class);
|
||||
$schema->allows('isManaged')->andReturn(true);
|
||||
$schema = SchemaFixture::managed();
|
||||
|
||||
return new RevisionsListAbility($schema);
|
||||
}
|
||||
|
||||
@@ -6,10 +6,10 @@ namespace LIT\MCP\Tests\Unit\Integrations\WordPress\Settings;
|
||||
|
||||
use Brain\Monkey\Functions;
|
||||
use LIT\MCP\Abilities\WriteFailed;
|
||||
use LIT\MCP\ChangeLog\ChangeLog;
|
||||
use LIT\MCP\Integrations\WordPress\Settings\SettingsWhitelist;
|
||||
use LIT\MCP\Integrations\WordPress\Settings\WpSettingsGetAbility;
|
||||
use LIT\MCP\Integrations\WordPress\Settings\WpSettingsUpdateAbility;
|
||||
use LIT\MCP\Tests\Support\FakeChangeLog;
|
||||
use LIT\MCP\Tests\Unit\TestCase;
|
||||
use Mockery;
|
||||
use RuntimeException;
|
||||
@@ -53,8 +53,7 @@ final class WpSettingsAbilitiesTest extends TestCase
|
||||
{
|
||||
$options = ['blogname' => 'Alt', 'blogdescription' => 'Praxis'];
|
||||
$this->optionStore($options);
|
||||
$log = Mockery::mock(ChangeLog::class);
|
||||
$log->allows('record')->andReturn(40);
|
||||
$log = new FakeChangeLog(40);
|
||||
$ability = new WpSettingsUpdateAbility(new SettingsWhitelist(), $log);
|
||||
$input = ['settings' => ['blogname' => 'Müller & Söhne', 'blogdescription' => 'Zahnärzte']];
|
||||
|
||||
@@ -81,8 +80,7 @@ final class WpSettingsAbilitiesTest extends TestCase
|
||||
{
|
||||
$options = ['blogname' => 'Alt'];
|
||||
$this->optionStore($options);
|
||||
$log = Mockery::mock(ChangeLog::class);
|
||||
$log->expects('record')->andThrow(new RuntimeException('log kaputt'));
|
||||
$log = new FakeChangeLog(1, new RuntimeException('log kaputt'));
|
||||
$file = (string) tempnam(sys_get_temp_dir(), 'lit-mcp-log');
|
||||
$previous = ini_set('error_log', $file);
|
||||
|
||||
@@ -96,6 +94,7 @@ final class WpSettingsAbilitiesTest extends TestCase
|
||||
self::assertTrue($result['ok']);
|
||||
self::assertNull($result['log_id']);
|
||||
self::assertCount(1, $result['warnings']);
|
||||
$log->assertRecorded([]);
|
||||
}
|
||||
|
||||
protected function tearDown(): void
|
||||
@@ -118,7 +117,7 @@ final class WpSettingsAbilitiesTest extends TestCase
|
||||
{
|
||||
Functions\expect('update_option')->never();
|
||||
|
||||
$result = (new WpSettingsUpdateAbility(new SettingsWhitelist(), Mockery::mock(ChangeLog::class)))
|
||||
$result = (new WpSettingsUpdateAbility(new SettingsWhitelist(), FakeChangeLog::forbidden()))
|
||||
->execute(['settings' => ['blogname' => 'Neu', 'admin_email' => 'x@y.de']]);
|
||||
|
||||
self::assertSame('lit_validation_failed', $result->get_error_code());
|
||||
@@ -129,7 +128,7 @@ final class WpSettingsAbilitiesTest extends TestCase
|
||||
{
|
||||
Functions\expect('update_option')->never();
|
||||
|
||||
$result = (new WpSettingsUpdateAbility(new SettingsWhitelist(), Mockery::mock(ChangeLog::class)))
|
||||
$result = (new WpSettingsUpdateAbility(new SettingsWhitelist(), FakeChangeLog::forbidden()))
|
||||
->execute(['settings' => ['template' => 'twentyten']]);
|
||||
|
||||
self::assertSame('lit_validation_failed', $result->get_error_code());
|
||||
@@ -162,8 +161,7 @@ final class WpSettingsAbilitiesTest extends TestCase
|
||||
});
|
||||
$GLOBALS['wp_rewrite'] = $rewrite;
|
||||
Functions\expect('flush_rewrite_rules')->once();
|
||||
$log = Mockery::mock(ChangeLog::class);
|
||||
$log->expects('record')->with('lit/wp-settings-update', 'option', 'blogname,permalink_structure', Mockery::type('string'))->andReturn(30);
|
||||
$log = new FakeChangeLog(30);
|
||||
|
||||
$result = (new WpSettingsUpdateAbility(new SettingsWhitelist(), $log))->execute(['settings' => [
|
||||
'blogname' => 'Neu',
|
||||
@@ -174,6 +172,11 @@ final class WpSettingsAbilitiesTest extends TestCase
|
||||
self::assertSame(['blogname', 'permalink_structure'], array_column($result['changed'], 'id'));
|
||||
self::assertSame(['blogname' => 'Alt', 'blogdescription' => 'Gleich', 'permalink_structure' => ''], $result['previous']);
|
||||
self::assertSame(30, $result['log_id']);
|
||||
$log->assertRecorded([
|
||||
'ability' => 'lit/wp-settings-update',
|
||||
'object_type' => 'option',
|
||||
'object_id' => 'blogname,permalink_structure',
|
||||
]);
|
||||
}
|
||||
|
||||
public function testDoesNotTreatAnAlreadyStoredValueAsAWriteFailure(): void
|
||||
@@ -190,8 +193,7 @@ final class WpSettingsAbilitiesTest extends TestCase
|
||||
'WPLANG' => '',
|
||||
][$key]);
|
||||
Functions\expect('update_option')->once()->with('blogname', 'Neu')->andReturn(true);
|
||||
$log = Mockery::mock(ChangeLog::class);
|
||||
$log->expects('record')->andReturn(31);
|
||||
$log = new FakeChangeLog(31);
|
||||
|
||||
$result = (new WpSettingsUpdateAbility(new SettingsWhitelist(), $log))->execute(['settings' => [
|
||||
'blogname' => 'Neu',
|
||||
@@ -200,6 +202,7 @@ final class WpSettingsAbilitiesTest extends TestCase
|
||||
|
||||
self::assertSame(['blogname'], array_column($result['changed'], 'id'));
|
||||
self::assertSame(31, $result['log_id']);
|
||||
$log->assertRecorded([]);
|
||||
}
|
||||
|
||||
public function testRestoresPreviousValuesWhenAWriteFailsPartway(): void
|
||||
@@ -211,9 +214,7 @@ final class WpSettingsAbilitiesTest extends TestCase
|
||||
Functions\expect('update_option')->once()->with('blogname', 'Neu')->andReturn(true);
|
||||
Functions\expect('update_option')->once()->with('blogdescription', 'Auch neu')->andReturn(false);
|
||||
Functions\expect('update_option')->once()->with('blogname', 'Alt')->andReturn(true);
|
||||
$log = Mockery::mock(ChangeLog::class);
|
||||
$log->shouldNotReceive('record');
|
||||
$log->shouldNotReceive('recordPartial');
|
||||
$log = FakeChangeLog::forbidden();
|
||||
|
||||
$error = $this->failure(new WpSettingsUpdateAbility(new SettingsWhitelist(), $log), [
|
||||
'blogname' => 'Neu',
|
||||
@@ -221,6 +222,8 @@ final class WpSettingsAbilitiesTest extends TestCase
|
||||
]);
|
||||
|
||||
self::assertSame('lit_write_failed', $error->get_error_code());
|
||||
$log->assertRecorded();
|
||||
$log->assertPartials();
|
||||
}
|
||||
|
||||
public function testReportsPartialWriteWhenRestoringAlsoFails(): void
|
||||
@@ -242,9 +245,7 @@ final class WpSettingsAbilitiesTest extends TestCase
|
||||
});
|
||||
Functions\expect('update_option')->once()->with('blogdescription', 'Auch neu')->andReturn(false);
|
||||
Functions\expect('update_option')->once()->with('blogname', 'Alt')->andReturn(false);
|
||||
$log = Mockery::mock(ChangeLog::class);
|
||||
$log->shouldNotReceive('record');
|
||||
$log->expects('recordPartial')->with('lit/wp-settings-update', 'option', 'blogname', Mockery::type('string'));
|
||||
$log = FakeChangeLog::partialsOnly();
|
||||
|
||||
$error = $this->failure(new WpSettingsUpdateAbility(new SettingsWhitelist(), $log), [
|
||||
'blogname' => 'Neu',
|
||||
@@ -254,6 +255,11 @@ final class WpSettingsAbilitiesTest extends TestCase
|
||||
self::assertSame('lit_partial_write', $error->get_error_code());
|
||||
self::assertStringContainsString('blogname', $error->get_error_message());
|
||||
self::assertStringContainsString('lit/wp-settings-get', $error->get_error_data()['hint']);
|
||||
$log->assertPartials([
|
||||
'ability' => 'lit/wp-settings-update',
|
||||
'object_type' => 'option',
|
||||
'object_id' => 'blogname',
|
||||
]);
|
||||
}
|
||||
|
||||
/** @param array<string, mixed> $settings */
|
||||
@@ -275,7 +281,7 @@ final class WpSettingsAbilitiesTest extends TestCase
|
||||
self::assertSame('lit_forbidden', (new WpSettingsGetAbility(new SettingsWhitelist()))->permission([])->get_error_code());
|
||||
self::assertSame(
|
||||
'lit_forbidden',
|
||||
(new WpSettingsUpdateAbility(new SettingsWhitelist(), Mockery::mock(ChangeLog::class)))->permission([])->get_error_code()
|
||||
(new WpSettingsUpdateAbility(new SettingsWhitelist(), FakeChangeLog::forbidden()))->permission([])->get_error_code()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,9 +8,10 @@ use Brain\Monkey\Actions;
|
||||
use Brain\Monkey\Functions;
|
||||
use LIT\MCP\Abilities\Rev;
|
||||
use LIT\MCP\ChangeLog\ChangeLog;
|
||||
use LIT\MCP\Integrations\WordPress\Schema\ContentSchema;
|
||||
use LIT\MCP\Integrations\WordPress\Status\PostCloner;
|
||||
use LIT\MCP\Integrations\WordPress\Status\PostDuplicateAbility;
|
||||
use LIT\MCP\Tests\Support\FakeChangeLog;
|
||||
use LIT\MCP\Tests\Support\SchemaFixture;
|
||||
use LIT\MCP\Tests\Unit\TestCase;
|
||||
use Mockery;
|
||||
use WP_Post;
|
||||
@@ -34,8 +35,7 @@ final class PostDuplicateAbilityTest extends TestCase
|
||||
|
||||
private function ability(PostCloner $cloner, ChangeLog $log): PostDuplicateAbility
|
||||
{
|
||||
$schema = Mockery::mock(ContentSchema::class);
|
||||
$schema->allows('isManaged')->andReturn(true);
|
||||
$schema = SchemaFixture::managed();
|
||||
|
||||
return new PostDuplicateAbility($schema, $cloner, $log);
|
||||
}
|
||||
@@ -45,8 +45,7 @@ final class PostDuplicateAbilityTest extends TestCase
|
||||
$cloner = Mockery::mock(PostCloner::class);
|
||||
$cloner->expects('duplicate')->with($this->original)->andReturn(77);
|
||||
Actions\expectDone('lit_mcp_after_save')->once()->with(77, 'lit/post-duplicate', ['post_id' => 5]);
|
||||
$log = Mockery::mock(ChangeLog::class);
|
||||
$log->expects('record')->with('lit/post-duplicate', 'page', '77', 'Kopie von "Team" (ID 5) angelegt', null)->andReturn(8);
|
||||
$log = new FakeChangeLog(8);
|
||||
|
||||
$result = $this->ability($cloner, $log)->execute(['post_id' => 5]);
|
||||
|
||||
@@ -55,6 +54,13 @@ final class PostDuplicateAbilityTest extends TestCase
|
||||
self::assertSame(8, $result['log_id']);
|
||||
self::assertSame(Rev::ofPost($this->copy), $result['rev']);
|
||||
self::assertSame([], $result['warnings']);
|
||||
$log->assertRecorded([
|
||||
'ability' => 'lit/post-duplicate',
|
||||
'object_type' => 'page',
|
||||
'object_id' => '77',
|
||||
'summary' => 'Kopie von "Team" (ID 5) angelegt',
|
||||
'revision_id' => null,
|
||||
]);
|
||||
}
|
||||
|
||||
public function testNeedsTheRightToCreateEntriesOfThatType(): void
|
||||
@@ -63,7 +69,7 @@ final class PostDuplicateAbilityTest extends TestCase
|
||||
$cloner = Mockery::mock(PostCloner::class);
|
||||
$cloner->expects('duplicate')->never();
|
||||
|
||||
$result = $this->ability($cloner, Mockery::mock(ChangeLog::class))->execute(['post_id' => 5]);
|
||||
$result = $this->ability($cloner, FakeChangeLog::forbidden())->execute(['post_id' => 5]);
|
||||
|
||||
self::assertSame('lit_forbidden', $result->get_error_code());
|
||||
}
|
||||
@@ -74,14 +80,14 @@ final class PostDuplicateAbilityTest extends TestCase
|
||||
$cloner = Mockery::mock(PostCloner::class);
|
||||
$cloner->expects('duplicate')->never();
|
||||
|
||||
$result = $this->ability($cloner, Mockery::mock(ChangeLog::class))->execute(['post_id' => 5]);
|
||||
$result = $this->ability($cloner, FakeChangeLog::forbidden())->execute(['post_id' => 5]);
|
||||
|
||||
self::assertSame('lit_validation_failed', $result->get_error_code());
|
||||
}
|
||||
|
||||
public function testIsIndirectAndNotIdempotent(): void
|
||||
{
|
||||
$ability = $this->ability(Mockery::mock(PostCloner::class), Mockery::mock(ChangeLog::class));
|
||||
$ability = $this->ability(Mockery::mock(PostCloner::class), FakeChangeLog::forbidden());
|
||||
|
||||
self::assertFalse($ability->isDirect());
|
||||
self::assertFalse($ability->annotations()['idempotent']);
|
||||
|
||||
@@ -7,10 +7,10 @@ namespace LIT\MCP\Tests\Unit\Integrations\WordPress\Status;
|
||||
use Brain\Monkey\Functions;
|
||||
use LIT\MCP\Abilities\WriteFailed;
|
||||
use LIT\MCP\ChangeLog\ChangeLog;
|
||||
use LIT\MCP\Integrations\WordPress\Schema\ContentSchema;
|
||||
use LIT\MCP\Integrations\WordPress\Status\PostPublishAbility;
|
||||
use LIT\MCP\Tests\Support\FakeChangeLog;
|
||||
use LIT\MCP\Tests\Support\SchemaFixture;
|
||||
use LIT\MCP\Tests\Unit\TestCase;
|
||||
use Mockery;
|
||||
use RuntimeException;
|
||||
use WP_Post;
|
||||
|
||||
@@ -18,8 +18,7 @@ final class PostPublishAbilityTest extends TestCase
|
||||
{
|
||||
private function ability(ChangeLog $log): PostPublishAbility
|
||||
{
|
||||
$schema = Mockery::mock(ContentSchema::class);
|
||||
$schema->allows('isManaged')->andReturn(true);
|
||||
$schema = SchemaFixture::managed();
|
||||
|
||||
return new PostPublishAbility($schema, $log);
|
||||
}
|
||||
@@ -37,14 +36,20 @@ final class PostPublishAbilityTest extends TestCase
|
||||
$this->stubPost(['post_status' => 'draft', 'post_date_gmt' => '0000-00-00 00:00:00']);
|
||||
Functions\expect('wp_update_post')->once()->with(['ID' => 5, 'post_status' => 'publish'], true)->andReturn(5);
|
||||
Functions\when('get_post_status')->justReturn('publish');
|
||||
$log = Mockery::mock(ChangeLog::class);
|
||||
$log->expects('record')->with('lit/post-publish', 'page', '5', '"Team" veröffentlicht', null)->andReturn(9);
|
||||
$log = new FakeChangeLog(9);
|
||||
|
||||
$result = $this->ability($log)->execute(['post_id' => 5]);
|
||||
|
||||
self::assertSame('published', $result['changed'][0]['action']);
|
||||
self::assertSame(9, $result['log_id']);
|
||||
self::assertSame('https://kunde.de/team/', $result['preview_url']);
|
||||
$log->assertRecorded([
|
||||
'ability' => 'lit/post-publish',
|
||||
'object_type' => 'page',
|
||||
'object_id' => '5',
|
||||
'summary' => '"Team" veröffentlicht',
|
||||
'revision_id' => null,
|
||||
]);
|
||||
}
|
||||
|
||||
public function testScheduledPostIsPublishedNowInsteadOfStayingFuture(): void
|
||||
@@ -59,8 +64,7 @@ final class PostPublishAbilityTest extends TestCase
|
||||
'edit_date' => true,
|
||||
], true)->andReturn(5);
|
||||
Functions\when('get_post_status')->justReturn('publish');
|
||||
$log = Mockery::mock(ChangeLog::class);
|
||||
$log->allows('record')->andReturn(1);
|
||||
$log = new FakeChangeLog(1);
|
||||
|
||||
$this->ability($log)->execute(['post_id' => 5]);
|
||||
}
|
||||
@@ -70,7 +74,7 @@ final class PostPublishAbilityTest extends TestCase
|
||||
$this->stubPost(['post_status' => 'publish']);
|
||||
Functions\expect('wp_update_post')->never();
|
||||
|
||||
$result = $this->ability(Mockery::mock(ChangeLog::class))->execute(['post_id' => 5]);
|
||||
$result = $this->ability(FakeChangeLog::forbidden())->execute(['post_id' => 5]);
|
||||
|
||||
self::assertSame([], $result['changed']);
|
||||
self::assertStringContainsString('bereits veröffentlicht', $result['summary']);
|
||||
@@ -82,8 +86,7 @@ final class PostPublishAbilityTest extends TestCase
|
||||
Functions\when('wp_update_post')->alias(static function (): void {
|
||||
throw new RuntimeException('save_post-Hook kaputt');
|
||||
});
|
||||
$log = Mockery::mock(ChangeLog::class);
|
||||
$log->expects('recordPartial')->with('lit/post-publish', 'page', '5', Mockery::type('string'));
|
||||
$log = FakeChangeLog::partialsOnly();
|
||||
|
||||
try {
|
||||
$this->ability($log)->execute(['post_id' => 5]);
|
||||
@@ -94,6 +97,7 @@ final class PostPublishAbilityTest extends TestCase
|
||||
self::assertStringContainsString('save_post-Hook kaputt', $e->getMessage());
|
||||
self::assertSame('lit_partial_write', $e->toError()->get_error_code());
|
||||
}
|
||||
$log->assertPartials(['ability' => 'lit/post-publish', 'object_type' => 'page', 'object_id' => '5']);
|
||||
}
|
||||
|
||||
public function testATrashedPostIsRefused(): void
|
||||
@@ -101,7 +105,7 @@ final class PostPublishAbilityTest extends TestCase
|
||||
$this->stubPost(['post_status' => 'trash']);
|
||||
Functions\expect('wp_update_post')->never();
|
||||
|
||||
$result = $this->ability(Mockery::mock(ChangeLog::class))->execute(['post_id' => 5]);
|
||||
$result = $this->ability(FakeChangeLog::forbidden())->execute(['post_id' => 5]);
|
||||
|
||||
self::assertSame('lit_validation_failed', $result->get_error_code());
|
||||
}
|
||||
@@ -111,6 +115,6 @@ final class PostPublishAbilityTest extends TestCase
|
||||
$this->stubPost(['post_status' => 'draft']);
|
||||
Functions\when('current_user_can')->alias(static fn (string $cap): bool => $cap !== 'publish_post');
|
||||
|
||||
self::assertSame('lit_forbidden', $this->ability(Mockery::mock(ChangeLog::class))->permission(['post_id' => 5])->get_error_code());
|
||||
self::assertSame('lit_forbidden', $this->ability(FakeChangeLog::forbidden())->permission(['post_id' => 5])->get_error_code());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,10 +8,11 @@ use Brain\Monkey\Functions;
|
||||
use LIT\MCP\Abilities\Rev;
|
||||
use LIT\MCP\Abilities\WriteFailed;
|
||||
use LIT\MCP\ChangeLog\ChangeLog;
|
||||
use LIT\MCP\Integrations\WordPress\Schema\ContentSchema;
|
||||
use LIT\MCP\Integrations\WordPress\Status\PostCloner;
|
||||
use LIT\MCP\Integrations\WordPress\Status\PostReplaceWithCopyAbility;
|
||||
use LIT\MCP\Integrations\WordPress\Status\ReplaceFailed;
|
||||
use LIT\MCP\Tests\Support\FakeChangeLog;
|
||||
use LIT\MCP\Tests\Support\SchemaFixture;
|
||||
use LIT\MCP\Tests\Unit\TestCase;
|
||||
use Mockery;
|
||||
use RuntimeException;
|
||||
@@ -39,8 +40,7 @@ final class PostReplaceWithCopyAbilityTest extends TestCase
|
||||
|
||||
private function ability(PostCloner $cloner, ChangeLog $log, bool $trash = true): PostReplaceWithCopyAbility
|
||||
{
|
||||
$schema = Mockery::mock(ContentSchema::class);
|
||||
$schema->allows('isManaged')->andReturn(true);
|
||||
$schema = SchemaFixture::managed();
|
||||
|
||||
return new PostReplaceWithCopyAbility($schema, $cloner, $log, static fn (): bool => $trash);
|
||||
}
|
||||
@@ -65,7 +65,7 @@ final class PostReplaceWithCopyAbilityTest extends TestCase
|
||||
$cloner = Mockery::mock(PostCloner::class);
|
||||
$cloner->expects('replace')->never();
|
||||
|
||||
$result = $this->ability($cloner, Mockery::mock(ChangeLog::class))
|
||||
$result = $this->ability($cloner, FakeChangeLog::forbidden())
|
||||
->execute(['original_id' => 5, 'copy_id' => 77, 'rev' => Rev::ofPost($this->original)]);
|
||||
|
||||
self::assertSame('lit_confirm_required', $result->get_error_code());
|
||||
@@ -77,7 +77,7 @@ final class PostReplaceWithCopyAbilityTest extends TestCase
|
||||
$cloner = Mockery::mock(PostCloner::class);
|
||||
$cloner->expects('replace')->never();
|
||||
|
||||
$result = $this->ability($cloner, Mockery::mock(ChangeLog::class))->execute($this->input());
|
||||
$result = $this->ability($cloner, FakeChangeLog::forbidden())->execute($this->input());
|
||||
|
||||
self::assertSame('lit_validation_failed', $result->get_error_code());
|
||||
}
|
||||
@@ -101,7 +101,7 @@ final class PostReplaceWithCopyAbilityTest extends TestCase
|
||||
$cloner->expects('backup')->never();
|
||||
$cloner->expects('replace')->never();
|
||||
|
||||
$result = $this->ability($cloner, Mockery::mock(ChangeLog::class))->execute($this->input());
|
||||
$result = $this->ability($cloner, FakeChangeLog::forbidden())->execute($this->input());
|
||||
|
||||
self::assertSame('lit_validation_failed', $result->get_error_code());
|
||||
}
|
||||
@@ -114,7 +114,7 @@ final class PostReplaceWithCopyAbilityTest extends TestCase
|
||||
$cloner->expects('backup')->never();
|
||||
$cloner->expects('replace')->never();
|
||||
|
||||
$result = $this->ability($cloner, Mockery::mock(ChangeLog::class))->execute($this->input());
|
||||
$result = $this->ability($cloner, FakeChangeLog::forbidden())->execute($this->input());
|
||||
|
||||
self::assertSame('lit_validation_failed', $result->get_error_code());
|
||||
self::assertArrayHasKey('original_id', $result->get_error_data()['fields']);
|
||||
@@ -129,8 +129,7 @@ final class PostReplaceWithCopyAbilityTest extends TestCase
|
||||
$cloner->allows('backup')->andReturn(88);
|
||||
$cloner->expects('replace');
|
||||
Functions\when('wp_trash_post')->justReturn(new WP_Post(['ID' => 77]));
|
||||
$log = Mockery::mock(ChangeLog::class);
|
||||
$log->allows('record')->andReturn(11);
|
||||
$log = new FakeChangeLog(11);
|
||||
|
||||
self::assertTrue($this->ability($cloner, $log)->execute($this->input())['ok']);
|
||||
}
|
||||
@@ -141,7 +140,7 @@ final class PostReplaceWithCopyAbilityTest extends TestCase
|
||||
$cloner->expects('replace')->never();
|
||||
Functions\expect('wp_save_post_revision')->never();
|
||||
|
||||
$result = $this->ability($cloner, Mockery::mock(ChangeLog::class))->execute($this->input(['rev' => 'veraltet']));
|
||||
$result = $this->ability($cloner, FakeChangeLog::forbidden())->execute($this->input(['rev' => 'veraltet']));
|
||||
|
||||
self::assertSame('lit_rev_mismatch', $result->get_error_code());
|
||||
}
|
||||
@@ -151,7 +150,7 @@ final class PostReplaceWithCopyAbilityTest extends TestCase
|
||||
$cloner = Mockery::mock(PostCloner::class);
|
||||
$cloner->expects('replace')->never();
|
||||
|
||||
$result = $this->ability($cloner, Mockery::mock(ChangeLog::class), false)->execute($this->input());
|
||||
$result = $this->ability($cloner, FakeChangeLog::forbidden(), false)->execute($this->input());
|
||||
|
||||
self::assertSame('lit_unsupported', $result->get_error_code());
|
||||
}
|
||||
@@ -181,8 +180,7 @@ final class PostReplaceWithCopyAbilityTest extends TestCase
|
||||
$order[] = 'trash';
|
||||
return new WP_Post(['ID' => 77]);
|
||||
});
|
||||
$log = Mockery::mock(ChangeLog::class);
|
||||
$log->expects('record')->with('lit/post-replace-with-copy', 'page', '5', Mockery::type('string'), 900)->andReturn(11);
|
||||
$log = new FakeChangeLog(11);
|
||||
|
||||
$result = $this->ability($cloner, $log)->execute($this->input());
|
||||
|
||||
@@ -194,6 +192,12 @@ final class PostReplaceWithCopyAbilityTest extends TestCase
|
||||
self::assertSame(Rev::ofPost($this->original), $result['rev']);
|
||||
self::assertSame(['replaced', 'trashed'], array_column($result['changed'], 'action'));
|
||||
self::assertSame([], $result['warnings']);
|
||||
$log->assertRecorded([
|
||||
'ability' => 'lit/post-replace-with-copy',
|
||||
'object_type' => 'page',
|
||||
'object_id' => '5',
|
||||
'revision_id' => 900,
|
||||
]);
|
||||
}
|
||||
|
||||
public function testAFailedTrashOfTheCopyIsAWarningOnly(): void
|
||||
@@ -204,8 +208,7 @@ final class PostReplaceWithCopyAbilityTest extends TestCase
|
||||
$cloner->allows('backup')->andReturn(88);
|
||||
$cloner->expects('replace');
|
||||
Functions\when('wp_trash_post')->justReturn(false);
|
||||
$log = Mockery::mock(ChangeLog::class);
|
||||
$log->allows('record')->andReturn(11);
|
||||
$log = new FakeChangeLog(11);
|
||||
|
||||
$result = $this->ability($cloner, $log)->execute($this->input());
|
||||
|
||||
@@ -225,7 +228,7 @@ final class PostReplaceWithCopyAbilityTest extends TestCase
|
||||
Functions\expect('wp_trash_post')->never();
|
||||
|
||||
try {
|
||||
$this->ability($cloner, Mockery::mock(ChangeLog::class))->execute($this->input());
|
||||
$this->ability($cloner, FakeChangeLog::forbidden())->execute($this->input());
|
||||
self::fail('WriteFailed expected');
|
||||
} catch (WriteFailed $e) {
|
||||
self::assertTrue($e->rolledBack);
|
||||
@@ -246,10 +249,7 @@ final class PostReplaceWithCopyAbilityTest extends TestCase
|
||||
$cloner->expects('replace')->andThrow(new RuntimeException('hook kaputt'));
|
||||
$cloner->expects('restore')->with($this->original, self::SNAPSHOT, PostCloner::PARTS)->andThrow(new RuntimeException('Restore incomplete: terms'));
|
||||
Functions\expect('wp_trash_post')->never();
|
||||
$log = Mockery::mock(ChangeLog::class);
|
||||
$log->expects('recordPartial')
|
||||
->with('lit/post-replace-with-copy', 'page', '5', Mockery::type('string'), 900)
|
||||
->andReturn(12);
|
||||
$log = FakeChangeLog::partialsOnly();
|
||||
|
||||
try {
|
||||
$this->ability($cloner, $log)->execute($this->input());
|
||||
@@ -264,6 +264,12 @@ final class PostReplaceWithCopyAbilityTest extends TestCase
|
||||
self::assertStringContainsString('Sicherung', $error->get_error_message());
|
||||
self::assertStringContainsString('88', $error->get_error_message());
|
||||
}
|
||||
$log->assertPartials([
|
||||
'ability' => 'lit/post-replace-with-copy',
|
||||
'object_type' => 'page',
|
||||
'object_id' => '5',
|
||||
'revision_id' => 900,
|
||||
]);
|
||||
}
|
||||
|
||||
public function testNeedsTheRightToCreateEntriesForTheBackup(): void
|
||||
@@ -272,7 +278,7 @@ final class PostReplaceWithCopyAbilityTest extends TestCase
|
||||
$cloner = Mockery::mock(PostCloner::class);
|
||||
$cloner->expects('backup')->never();
|
||||
$cloner->expects('replace')->never();
|
||||
$ability = $this->ability($cloner, Mockery::mock(ChangeLog::class));
|
||||
$ability = $this->ability($cloner, FakeChangeLog::forbidden());
|
||||
|
||||
self::assertSame('lit_forbidden', $ability->permission($this->input())->get_error_code());
|
||||
self::assertSame('lit_forbidden', $ability->execute($this->input())->get_error_code());
|
||||
@@ -289,7 +295,7 @@ final class PostReplaceWithCopyAbilityTest extends TestCase
|
||||
Functions\expect('wp_trash_post')->never();
|
||||
|
||||
try {
|
||||
$this->ability($cloner, Mockery::mock(ChangeLog::class))->execute($this->input());
|
||||
$this->ability($cloner, FakeChangeLog::forbidden())->execute($this->input());
|
||||
self::fail('WriteFailed expected');
|
||||
} catch (WriteFailed $e) {
|
||||
self::assertSame('lit_write_failed', $e->toError()->get_error_code());
|
||||
@@ -298,7 +304,7 @@ final class PostReplaceWithCopyAbilityTest extends TestCase
|
||||
|
||||
public function testRequiresRevAndIsDestructive(): void
|
||||
{
|
||||
$ability = $this->ability(Mockery::mock(PostCloner::class), Mockery::mock(ChangeLog::class));
|
||||
$ability = $this->ability(Mockery::mock(PostCloner::class), FakeChangeLog::forbidden());
|
||||
|
||||
self::assertContains('rev', $ability->inputSchema()['required']);
|
||||
self::assertContains('backup_id', $ability->outputSchema()['required']);
|
||||
|
||||
@@ -8,10 +8,10 @@ use Brain\Monkey\Functions;
|
||||
use DateTimeZone;
|
||||
use LIT\MCP\Abilities\WriteFailed;
|
||||
use LIT\MCP\ChangeLog\ChangeLog;
|
||||
use LIT\MCP\Integrations\WordPress\Schema\ContentSchema;
|
||||
use LIT\MCP\Integrations\WordPress\Status\PostScheduleAbility;
|
||||
use LIT\MCP\Tests\Support\FakeChangeLog;
|
||||
use LIT\MCP\Tests\Support\SchemaFixture;
|
||||
use LIT\MCP\Tests\Unit\TestCase;
|
||||
use Mockery;
|
||||
use RuntimeException;
|
||||
use WP_Post;
|
||||
|
||||
@@ -29,8 +29,7 @@ final class PostScheduleAbilityTest extends TestCase
|
||||
|
||||
private function ability(ChangeLog $log): PostScheduleAbility
|
||||
{
|
||||
$schema = Mockery::mock(ContentSchema::class);
|
||||
$schema->allows('isManaged')->andReturn(true);
|
||||
$schema = SchemaFixture::managed();
|
||||
|
||||
return new PostScheduleAbility($schema, $log);
|
||||
}
|
||||
@@ -45,13 +44,13 @@ final class PostScheduleAbilityTest extends TestCase
|
||||
'edit_date' => true,
|
||||
], true)->andReturn(5);
|
||||
Functions\when('get_post_status')->justReturn('future');
|
||||
$log = Mockery::mock(ChangeLog::class);
|
||||
$log->expects('record')->andReturn(4);
|
||||
$log = new FakeChangeLog(4);
|
||||
|
||||
$result = $this->ability($log)->execute(['post_id' => 5, 'date' => '2099-06-01 09:30']);
|
||||
|
||||
self::assertSame('scheduled', $result['changed'][0]['action']);
|
||||
self::assertStringContainsString('2099-06-01 09:30', $result['summary']);
|
||||
$log->assertRecorded([]);
|
||||
}
|
||||
|
||||
public function testWarnsThatAPrivatePostBecomesPublic(): void
|
||||
@@ -59,8 +58,7 @@ final class PostScheduleAbilityTest extends TestCase
|
||||
Functions\when('get_post')->justReturn(new WP_Post(['ID' => 5, 'post_type' => 'post', 'post_title' => 'Intern', 'post_status' => 'private']));
|
||||
Functions\when('wp_update_post')->justReturn(5);
|
||||
Functions\when('get_post_status')->justReturn('future');
|
||||
$log = Mockery::mock(ChangeLog::class);
|
||||
$log->allows('record')->andReturn(4);
|
||||
$log = new FakeChangeLog(4);
|
||||
|
||||
$result = $this->ability($log)->execute(['post_id' => 5, 'date' => '2099-06-01 09:30']);
|
||||
|
||||
@@ -73,8 +71,7 @@ final class PostScheduleAbilityTest extends TestCase
|
||||
{
|
||||
Functions\when('wp_update_post')->justReturn(5);
|
||||
Functions\when('get_post_status')->justReturn('future');
|
||||
$log = Mockery::mock(ChangeLog::class);
|
||||
$log->allows('record')->andReturn(4);
|
||||
$log = new FakeChangeLog(4);
|
||||
|
||||
$result = $this->ability($log)->execute(['post_id' => 5, 'date' => '2099-06-01 09:30']);
|
||||
|
||||
@@ -86,8 +83,7 @@ final class PostScheduleAbilityTest extends TestCase
|
||||
Functions\when('wp_update_post')->alias(static function (): void {
|
||||
throw new RuntimeException('save_post-Hook kaputt');
|
||||
});
|
||||
$log = Mockery::mock(ChangeLog::class);
|
||||
$log->expects('recordPartial')->with('lit/post-schedule', 'post', '5', Mockery::type('string'));
|
||||
$log = FakeChangeLog::partialsOnly();
|
||||
|
||||
try {
|
||||
$this->ability($log)->execute(['post_id' => 5, 'date' => '2099-06-01 09:30']);
|
||||
@@ -98,6 +94,7 @@ final class PostScheduleAbilityTest extends TestCase
|
||||
self::assertStringContainsString('save_post-Hook kaputt', $e->getMessage());
|
||||
self::assertSame('lit_partial_write', $e->toError()->get_error_code());
|
||||
}
|
||||
$log->assertPartials(['ability' => 'lit/post-schedule', 'object_type' => 'post', 'object_id' => '5']);
|
||||
}
|
||||
|
||||
public function testATrashedPostIsRefused(): void
|
||||
@@ -105,7 +102,7 @@ final class PostScheduleAbilityTest extends TestCase
|
||||
Functions\when('get_post')->justReturn(new WP_Post(['ID' => 5, 'post_type' => 'post', 'post_status' => 'trash']));
|
||||
Functions\expect('wp_update_post')->never();
|
||||
|
||||
$result = $this->ability(Mockery::mock(ChangeLog::class))->execute(['post_id' => 5, 'date' => '2099-06-01 09:30']);
|
||||
$result = $this->ability(FakeChangeLog::forbidden())->execute(['post_id' => 5, 'date' => '2099-06-01 09:30']);
|
||||
|
||||
self::assertSame('lit_validation_failed', $result->get_error_code());
|
||||
}
|
||||
@@ -113,7 +110,7 @@ final class PostScheduleAbilityTest extends TestCase
|
||||
public function testPastAndImpossibleDatesAreRejected(): void
|
||||
{
|
||||
Functions\expect('wp_update_post')->never();
|
||||
$ability = $this->ability(Mockery::mock(ChangeLog::class));
|
||||
$ability = $this->ability(FakeChangeLog::forbidden());
|
||||
|
||||
$past = $ability->execute(['post_id' => 5, 'date' => '2020-01-01 10:00']);
|
||||
$impossible = $ability->execute(['post_id' => 5, 'date' => '2099-13-45 10:00']);
|
||||
@@ -131,7 +128,7 @@ final class PostScheduleAbilityTest extends TestCase
|
||||
->setTimezone(new DateTimeZone('Europe/Berlin'));
|
||||
Functions\when('get_post_status')->justReturn('future');
|
||||
|
||||
$result = $this->ability(Mockery::mock(ChangeLog::class))
|
||||
$result = $this->ability(FakeChangeLog::forbidden())
|
||||
->execute(['post_id' => 5, 'date' => $soon->format('Y-m-d H:i')]);
|
||||
|
||||
self::assertSame('lit_validation_failed', $result->get_error_code());
|
||||
|
||||
@@ -7,10 +7,10 @@ namespace LIT\MCP\Tests\Unit\Integrations\WordPress\Status;
|
||||
use Brain\Monkey\Functions;
|
||||
use LIT\MCP\Abilities\WriteFailed;
|
||||
use LIT\MCP\ChangeLog\ChangeLog;
|
||||
use LIT\MCP\Integrations\WordPress\Schema\ContentSchema;
|
||||
use LIT\MCP\Integrations\WordPress\Status\PostTrashAbility;
|
||||
use LIT\MCP\Tests\Support\FakeChangeLog;
|
||||
use LIT\MCP\Tests\Support\SchemaFixture;
|
||||
use LIT\MCP\Tests\Unit\TestCase;
|
||||
use Mockery;
|
||||
use RuntimeException;
|
||||
use WP_Post;
|
||||
|
||||
@@ -33,8 +33,7 @@ final class PostTrashAbilityTest extends TestCase
|
||||
{
|
||||
Functions\when('get_post')->justReturn(new WP_Post(['ID' => 5, 'post_type' => 'page', 'post_title' => 'Alt', 'post_status' => 'publish']));
|
||||
Functions\when('current_user_can')->justReturn(true);
|
||||
$schema = Mockery::mock(ContentSchema::class);
|
||||
$schema->allows('isManaged')->andReturn(true);
|
||||
$schema = SchemaFixture::managed();
|
||||
|
||||
return new PostTrashAbility($schema, $log);
|
||||
}
|
||||
@@ -43,7 +42,7 @@ final class PostTrashAbilityTest extends TestCase
|
||||
{
|
||||
Functions\expect('wp_trash_post')->never();
|
||||
|
||||
$result = $this->ability(Mockery::mock(ChangeLog::class))->execute(['post_id' => 5]);
|
||||
$result = $this->ability(FakeChangeLog::forbidden())->execute(['post_id' => 5]);
|
||||
|
||||
self::assertSame('lit_confirm_required', $result->get_error_code());
|
||||
}
|
||||
@@ -52,13 +51,19 @@ final class PostTrashAbilityTest extends TestCase
|
||||
{
|
||||
Functions\expect('wp_trash_post')->once()->with(5)->andReturn(new WP_Post(['ID' => 5]));
|
||||
Functions\expect('wp_delete_post')->never();
|
||||
$log = Mockery::mock(ChangeLog::class);
|
||||
$log->expects('record')->with('lit/post-trash', 'page', '5', '"Alt" in den Papierkorb gelegt', null)->andReturn(2);
|
||||
$log = new FakeChangeLog(2);
|
||||
|
||||
$result = $this->ability($log)->execute(['post_id' => 5, 'confirm' => true]);
|
||||
|
||||
self::assertSame('trashed', $result['changed'][0]['action']);
|
||||
self::assertStringContainsString('Papierkorb', $result['summary']);
|
||||
$log->assertRecorded([
|
||||
'ability' => 'lit/post-trash',
|
||||
'object_type' => 'page',
|
||||
'object_id' => '5',
|
||||
'summary' => '"Alt" in den Papierkorb gelegt',
|
||||
'revision_id' => null,
|
||||
]);
|
||||
}
|
||||
|
||||
public function testRefusesWhenTheTrashIsDisabledInsteadOfDeleting(): void
|
||||
@@ -66,9 +71,8 @@ final class PostTrashAbilityTest extends TestCase
|
||||
Functions\when('get_post')->justReturn(new WP_Post(['ID' => 5, 'post_type' => 'page', 'post_status' => 'publish']));
|
||||
Functions\when('current_user_can')->justReturn(true);
|
||||
Functions\expect('wp_trash_post')->never();
|
||||
$schema = Mockery::mock(ContentSchema::class);
|
||||
$schema->allows('isManaged')->andReturn(true);
|
||||
$ability = new PostTrashAbility($schema, Mockery::mock(ChangeLog::class), static fn (): bool => false);
|
||||
$schema = SchemaFixture::managed();
|
||||
$ability = new PostTrashAbility($schema, FakeChangeLog::forbidden(), static fn (): bool => false);
|
||||
|
||||
$result = $ability->execute(['post_id' => 5, 'confirm' => true]);
|
||||
|
||||
@@ -80,8 +84,7 @@ final class PostTrashAbilityTest extends TestCase
|
||||
Functions\when('wp_trash_post')->alias(static function (): void {
|
||||
throw new RuntimeException('save_post-Hook kaputt');
|
||||
});
|
||||
$log = Mockery::mock(ChangeLog::class);
|
||||
$log->expects('recordPartial')->with('lit/post-trash', 'page', '5', Mockery::type('string'));
|
||||
$log = FakeChangeLog::partialsOnly();
|
||||
|
||||
try {
|
||||
$this->ability($log)->execute(['post_id' => 5, 'confirm' => true]);
|
||||
@@ -92,11 +95,12 @@ final class PostTrashAbilityTest extends TestCase
|
||||
self::assertStringContainsString('save_post-Hook kaputt', $e->getMessage());
|
||||
self::assertSame('lit_partial_write', $e->toError()->get_error_code());
|
||||
}
|
||||
$log->assertPartials(['ability' => 'lit/post-trash', 'object_type' => 'page', 'object_id' => '5']);
|
||||
}
|
||||
|
||||
public function testAnAlreadyTrashedPostIsANoOp(): void
|
||||
{
|
||||
$ability = $this->ability(Mockery::mock(ChangeLog::class));
|
||||
$ability = $this->ability(FakeChangeLog::forbidden());
|
||||
Functions\when('get_post')->justReturn(new WP_Post(['ID' => 5, 'post_type' => 'page', 'post_title' => 'Alt', 'post_status' => 'trash']));
|
||||
Functions\expect('wp_trash_post')->never();
|
||||
|
||||
@@ -110,8 +114,7 @@ final class PostTrashAbilityTest extends TestCase
|
||||
{
|
||||
$this->options(['show_on_front' => 'page', 'page_on_front' => '5', 'page_for_posts' => '9']);
|
||||
Functions\when('wp_trash_post')->justReturn(new WP_Post(['ID' => 5]));
|
||||
$log = Mockery::mock(ChangeLog::class);
|
||||
$log->allows('record')->andReturn(3);
|
||||
$log = new FakeChangeLog(3);
|
||||
$ability = $this->ability($log);
|
||||
|
||||
$confirm = $ability->execute(['post_id' => 5]);
|
||||
@@ -141,8 +144,7 @@ final class PostTrashAbilityTest extends TestCase
|
||||
: []
|
||||
);
|
||||
Functions\when('wp_trash_post')->justReturn(new WP_Post(['ID' => 5]));
|
||||
$log = Mockery::mock(ChangeLog::class);
|
||||
$log->allows('record')->andReturn(3);
|
||||
$log = new FakeChangeLog(3);
|
||||
|
||||
$result = $this->ability($log)->execute(['post_id' => 5, 'confirm' => true]);
|
||||
|
||||
@@ -153,7 +155,7 @@ final class PostTrashAbilityTest extends TestCase
|
||||
|
||||
public function testIsDestructiveAndIndirect(): void
|
||||
{
|
||||
$ability = $this->ability(Mockery::mock(ChangeLog::class));
|
||||
$ability = $this->ability(FakeChangeLog::forbidden());
|
||||
|
||||
self::assertTrue($ability->annotations()['destructive']);
|
||||
self::assertFalse($ability->isDirect());
|
||||
|
||||
@@ -7,10 +7,10 @@ namespace LIT\MCP\Tests\Unit\Integrations\WordPress\Status;
|
||||
use Brain\Monkey\Functions;
|
||||
use LIT\MCP\Abilities\WriteFailed;
|
||||
use LIT\MCP\ChangeLog\ChangeLog;
|
||||
use LIT\MCP\Integrations\WordPress\Schema\ContentSchema;
|
||||
use LIT\MCP\Integrations\WordPress\Status\PostUnpublishAbility;
|
||||
use LIT\MCP\Tests\Support\FakeChangeLog;
|
||||
use LIT\MCP\Tests\Support\SchemaFixture;
|
||||
use LIT\MCP\Tests\Unit\TestCase;
|
||||
use Mockery;
|
||||
use RuntimeException;
|
||||
use WP_Post;
|
||||
|
||||
@@ -22,8 +22,7 @@ final class PostUnpublishAbilityTest extends TestCase
|
||||
Functions\when('current_user_can')->justReturn(true);
|
||||
Functions\when('get_preview_post_link')->justReturn('https://kunde.de/?p=5&preview=true');
|
||||
Functions\when('get_edit_post_link')->justReturn('https://kunde.de/wp-admin/post.php?post=5&action=edit');
|
||||
$schema = Mockery::mock(ContentSchema::class);
|
||||
$schema->allows('isManaged')->andReturn(true);
|
||||
$schema = SchemaFixture::managed();
|
||||
|
||||
return new PostUnpublishAbility($schema, $log);
|
||||
}
|
||||
@@ -31,12 +30,12 @@ final class PostUnpublishAbilityTest extends TestCase
|
||||
public function testPublishedPostBecomesDraft(): void
|
||||
{
|
||||
Functions\expect('wp_update_post')->once()->with(['ID' => 5, 'post_status' => 'draft'], true)->andReturn(5);
|
||||
$log = Mockery::mock(ChangeLog::class);
|
||||
$log->expects('record')->andReturn(3);
|
||||
$log = new FakeChangeLog(3);
|
||||
|
||||
$result = $this->ability($log, 'publish')->execute(['post_id' => 5]);
|
||||
|
||||
self::assertSame('unpublished', $result['changed'][0]['action']);
|
||||
$log->assertRecorded([]);
|
||||
}
|
||||
|
||||
public function testAHookThrowingDuringTheWriteIsAPartialWrite(): void
|
||||
@@ -44,8 +43,7 @@ final class PostUnpublishAbilityTest extends TestCase
|
||||
Functions\when('wp_update_post')->alias(static function (): void {
|
||||
throw new RuntimeException('save_post-Hook kaputt');
|
||||
});
|
||||
$log = Mockery::mock(ChangeLog::class);
|
||||
$log->expects('recordPartial')->with('lit/post-unpublish', 'page', '5', Mockery::type('string'));
|
||||
$log = FakeChangeLog::partialsOnly();
|
||||
|
||||
try {
|
||||
$this->ability($log, 'publish')->execute(['post_id' => 5]);
|
||||
@@ -56,13 +54,14 @@ final class PostUnpublishAbilityTest extends TestCase
|
||||
self::assertStringContainsString('save_post-Hook kaputt', $e->getMessage());
|
||||
self::assertSame('lit_partial_write', $e->toError()->get_error_code());
|
||||
}
|
||||
$log->assertPartials(['ability' => 'lit/post-unpublish', 'object_type' => 'page', 'object_id' => '5']);
|
||||
}
|
||||
|
||||
public function testATrashedPostIsRefusedInsteadOfBecomingADraft(): void
|
||||
{
|
||||
Functions\expect('wp_update_post')->never();
|
||||
|
||||
$result = $this->ability(Mockery::mock(ChangeLog::class), 'trash')->execute(['post_id' => 5]);
|
||||
$result = $this->ability(FakeChangeLog::forbidden(), 'trash')->execute(['post_id' => 5]);
|
||||
|
||||
self::assertSame('lit_validation_failed', $result->get_error_code());
|
||||
}
|
||||
@@ -71,7 +70,7 @@ final class PostUnpublishAbilityTest extends TestCase
|
||||
{
|
||||
Functions\expect('wp_update_post')->never();
|
||||
|
||||
$result = $this->ability(Mockery::mock(ChangeLog::class), 'draft')->execute(['post_id' => 5]);
|
||||
$result = $this->ability(FakeChangeLog::forbidden(), 'draft')->execute(['post_id' => 5]);
|
||||
|
||||
self::assertSame([], $result['changed']);
|
||||
}
|
||||
|
||||
@@ -6,10 +6,11 @@ namespace LIT\MCP\Tests\Unit\Integrations\WordPress;
|
||||
|
||||
use LIT\MCP\Abilities\Ability;
|
||||
use Brain\Monkey\Functions;
|
||||
use LIT\MCP\ChangeLog\ChangeLog;
|
||||
use LIT\MCP\Integrations\WordPress\Content\ContentComposer;
|
||||
use LIT\MCP\Integrations\WordPress\Schema\ContentSchema;
|
||||
use LIT\MCP\Integrations\WordPress\WordPressIntegration;
|
||||
use LIT\MCP\Tests\Support\FakeChangeLog;
|
||||
use LIT\MCP\Tests\Support\SchemaFixture;
|
||||
use LIT\MCP\Tests\Unit\TestCase;
|
||||
use Mockery;
|
||||
|
||||
@@ -42,7 +43,7 @@ final class WordPressIntegrationTest extends TestCase
|
||||
|
||||
public function testProvidesTheWordPressAbilitiesInOrder(): void
|
||||
{
|
||||
$integration = new WordPressIntegration(Mockery::mock(ContentSchema::class), Mockery::mock(ChangeLog::class));
|
||||
$integration = new WordPressIntegration(Mockery::mock(ContentSchema::class), FakeChangeLog::forbidden());
|
||||
|
||||
self::assertSame('wordpress', $integration->id());
|
||||
self::assertTrue($integration->isAvailable());
|
||||
@@ -54,7 +55,7 @@ final class WordPressIntegrationTest extends TestCase
|
||||
|
||||
public function testEveryAbilityHasAnObjectInputSchemaThatRejectsUnknownKeys(): void
|
||||
{
|
||||
$integration = new WordPressIntegration(Mockery::mock(ContentSchema::class), Mockery::mock(ChangeLog::class));
|
||||
$integration = new WordPressIntegration(Mockery::mock(ContentSchema::class), FakeChangeLog::forbidden());
|
||||
|
||||
foreach ($integration->abilities() as $ability) {
|
||||
$schema = $ability->inputSchema();
|
||||
@@ -68,11 +69,10 @@ final class WordPressIntegrationTest extends TestCase
|
||||
{
|
||||
Functions\when('get_post_type_object')->justReturn((object) ['cap' => (object) ['create_posts' => 'edit_pages']]);
|
||||
Functions\when('current_user_can')->justReturn(true);
|
||||
$schema = Mockery::mock(ContentSchema::class);
|
||||
$schema->allows('isManaged')->andReturn(true);
|
||||
$schema = SchemaFixture::managed();
|
||||
$composer = Mockery::mock(ContentComposer::class);
|
||||
$composer->expects('available')->andReturn(false);
|
||||
$integration = new WordPressIntegration($schema, Mockery::mock(ChangeLog::class), $composer);
|
||||
$integration = new WordPressIntegration($schema, FakeChangeLog::forbidden(), $composer);
|
||||
|
||||
$create = array_values(array_filter(
|
||||
$integration->abilities(),
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace LIT\MCP\Tests\Unit\Support;
|
||||
|
||||
use LIT\MCP\Tests\Support\FakeChangeLog;
|
||||
use LIT\MCP\Tests\Unit\TestCase;
|
||||
use LogicException;
|
||||
use PHPUnit\Framework\AssertionFailedError;
|
||||
use RuntimeException;
|
||||
|
||||
final class FakeChangeLogTest extends TestCase
|
||||
{
|
||||
public function testRecordsCallsWithIncreasingIds(): void
|
||||
{
|
||||
$log = new FakeChangeLog(41);
|
||||
|
||||
self::assertSame(41, $log->record('lit/a', 'page', '5', 'eins', 811));
|
||||
self::assertSame(42, $log->record('lit/a', 'page', '6', 'zwei'));
|
||||
$log->assertRecorded(
|
||||
['object_id' => '5', 'summary' => 'eins', 'revision_id' => 811, 'result' => 'ok'],
|
||||
['object_id' => '6', 'revision_id' => null]
|
||||
);
|
||||
self::assertSame(['eins', 'zwei'], $log->summaries());
|
||||
}
|
||||
|
||||
public function testAFailureIsThrownAfterTheCallIsNoted(): void
|
||||
{
|
||||
$log = new FakeChangeLog(1, new RuntimeException('db weg'));
|
||||
|
||||
try {
|
||||
$log->record('lit/a', 'page', '5', 'x');
|
||||
self::fail('RuntimeException expected');
|
||||
} catch (RuntimeException $e) {
|
||||
self::assertSame('db weg', $e->getMessage());
|
||||
}
|
||||
$log->assertRecorded(['ability' => 'lit/a']);
|
||||
}
|
||||
|
||||
public function testAssertRecordedChecksTheNumberOfCalls(): void
|
||||
{
|
||||
$log = new FakeChangeLog();
|
||||
$log->record('lit/a', 'page', '5', 'x');
|
||||
|
||||
$this->expectException(AssertionFailedError::class);
|
||||
$log->assertRecorded([], []);
|
||||
}
|
||||
|
||||
public function testAssertPartialsChecksTheNamedArguments(): void
|
||||
{
|
||||
$log = FakeChangeLog::partialsOnly();
|
||||
$log->recordPartial('lit/a', 'page', '5', 'teilweise', 811);
|
||||
$log->assertPartials(['ability' => 'lit/a', 'revision_id' => 811]);
|
||||
|
||||
$this->expectException(AssertionFailedError::class);
|
||||
$log->assertPartials(['object_id' => '6']);
|
||||
}
|
||||
|
||||
public function testACallTheFakeDoesNotAllowThrowsAndFailsTheTestEvenWhenSwallowed(): void
|
||||
{
|
||||
$log = FakeChangeLog::forbidden();
|
||||
|
||||
try {
|
||||
$log->record('lit/a', 'page', '5', 'x');
|
||||
self::fail('LogicException expected');
|
||||
} catch (LogicException $e) {
|
||||
self::assertStringContainsString('record(lit/a, page, 5)', $e->getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
FakeChangeLog::verify();
|
||||
self::fail('verify() must fail');
|
||||
} catch (AssertionFailedError $e) {
|
||||
self::assertStringContainsString('Unexpected change log calls', $e->getMessage());
|
||||
}
|
||||
FakeChangeLog::verify();
|
||||
}
|
||||
|
||||
public function testRecordOnlyFakesRefusePartialsAndPartialsOnlyFakesRefuseRecords(): void
|
||||
{
|
||||
foreach ([[new FakeChangeLog(), 'recordPartial'], [FakeChangeLog::partialsOnly(), 'record']] as [$log, $method]) {
|
||||
try {
|
||||
$log->$method('lit/a', 'page', '5', 'x');
|
||||
self::fail($method . ' must be refused');
|
||||
} catch (LogicException $e) {
|
||||
self::assertStringContainsString($method, $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
$this->expectException(AssertionFailedError::class);
|
||||
$this->expectExceptionMessage('Unexpected change log calls: recordPartial(lit/a, page, 5); record(lit/a, page, 5)');
|
||||
FakeChangeLog::verify();
|
||||
}
|
||||
|
||||
public function testAnyAllowsBoth(): void
|
||||
{
|
||||
$log = FakeChangeLog::any(9);
|
||||
|
||||
self::assertSame(9, $log->record('lit/a', 'page', '5', 'x'));
|
||||
$log->recordPartial('lit/a', 'page', '5', 'y');
|
||||
$log->assertPartials(['summary' => 'y']);
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ namespace LIT\MCP\Tests\Unit;
|
||||
|
||||
use Brain\Monkey;
|
||||
use Brain\Monkey\Functions;
|
||||
use LIT\MCP\Tests\Support\FakeChangeLog;
|
||||
use Mockery\Adapter\Phpunit\MockeryPHPUnitIntegration;
|
||||
use PHPUnit\Framework\TestCase as BaseTestCase;
|
||||
|
||||
@@ -35,5 +36,6 @@ abstract class TestCase extends BaseTestCase
|
||||
{
|
||||
Monkey\tearDown();
|
||||
parent::tearDown();
|
||||
FakeChangeLog::verify();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user