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:
2026-09-26 17:53:54 +02:00
co-authored by Claude Opus 5.5
parent 3d96a41366
commit 72eeaa46ad
34 changed files with 725 additions and 353 deletions
@@ -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()
);
}
}