feat: wp lit-mcp divi-check with diff and reference update
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,174 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace LIT\MCP\Tests\Unit\Cli;
|
||||
|
||||
use Brain\Monkey\Functions;
|
||||
use LIT\MCP\Cli\DiviCheckCommand;
|
||||
use LIT\MCP\Integrations\Divi\Release\CheckReport;
|
||||
use LIT\MCP\Integrations\Divi\Release\CheckReportStore;
|
||||
use LIT\MCP\Integrations\Divi\Release\CheckStep;
|
||||
use LIT\MCP\Integrations\Divi\Release\CompatibilityCheck;
|
||||
use LIT\MCP\Integrations\Divi\Release\DiviReference;
|
||||
use LIT\MCP\Tests\Unit\TestCase;
|
||||
use Mockery;
|
||||
|
||||
final class DiviCheckCommandTest extends TestCase
|
||||
{
|
||||
/** @var list<string> */
|
||||
private array $lines = [];
|
||||
|
||||
private string $themeDir = '';
|
||||
private string $sourceDir = '';
|
||||
private string $expectedFile = '';
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
$this->lines = [];
|
||||
$base = sys_get_temp_dir() . '/lit-cli-' . uniqid();
|
||||
$this->themeDir = $base . '/Divi';
|
||||
$this->sourceDir = $base . '/reference';
|
||||
mkdir($this->themeDir . '/includes/builder', 0777, true);
|
||||
mkdir($this->sourceDir, 0777, true);
|
||||
$this->expectedFile = $base . '/fingerprints.json';
|
||||
Functions\when('current_user_can')->justReturn(true);
|
||||
Functions\when('get_current_user_id')->justReturn(1);
|
||||
Functions\when('delete_transient')->justReturn(true);
|
||||
}
|
||||
|
||||
protected function tearDown(): void
|
||||
{
|
||||
exec('rm -rf ' . escapeshellarg(dirname($this->themeDir)));
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
/** @param array<string, list<string>> $problems Step key => problems. */
|
||||
private function command(array $problems = []): DiviCheckCommand
|
||||
{
|
||||
$steps = array_map(
|
||||
static fn (string $key): CheckStep => new CheckStep($key, $problems[$key] ?? []),
|
||||
[CheckStep::MANIFEST, CheckStep::MIRRORS, CheckStep::CATALOG, CheckStep::FORMAT, CheckStep::WRITE]
|
||||
);
|
||||
$check = Mockery::mock(CompatibilityCheck::class);
|
||||
$check->allows('run')->andReturn(new CheckReport('r1', 'd', 1, '5.3.0', '0.6.0', 'k', $steps));
|
||||
$reports = Mockery::mock(CheckReportStore::class);
|
||||
$reports->allows('save');
|
||||
|
||||
return new DiviCheckCommand(
|
||||
static fn () => $check,
|
||||
$reports,
|
||||
function (string $line): void {
|
||||
$this->lines[] = $line;
|
||||
},
|
||||
fn (): ?string => $this->themeDir,
|
||||
$this->expectedFile,
|
||||
fn (): ?string => $this->sourceDir
|
||||
);
|
||||
}
|
||||
|
||||
public function testNeedsAnAdministrator(): void
|
||||
{
|
||||
Functions\when('current_user_can')->justReturn(false);
|
||||
|
||||
self::assertSame(1, $this->command()->run([]));
|
||||
self::assertStringContainsString('--user=', implode("\n", $this->lines));
|
||||
}
|
||||
|
||||
public function testPrintsTheStepsAndSucceedsWhenGreen(): void
|
||||
{
|
||||
self::assertSame(0, $this->command()->run([]));
|
||||
self::assertContains('✓ Schreibtest auf einer Wegwerfseite', $this->lines);
|
||||
}
|
||||
|
||||
public function testFailsWhenAStepIsRed(): void
|
||||
{
|
||||
self::assertSame(1, $this->command([CheckStep::CATALOG => ['divi/text: unbekanntes Modul']])->run([]));
|
||||
self::assertContains('✗ Modulkatalog (Kurzform-Pfade)', $this->lines);
|
||||
self::assertContains(' divi/text: unbekanntes Modul', $this->lines);
|
||||
}
|
||||
|
||||
public function testUpdateReferenceRefusesWhenMoreThanFingerprintsIsRed(): void
|
||||
{
|
||||
$code = $this->command([CheckStep::FORMAT => ['kaputt']])->run(['update-reference' => true]);
|
||||
|
||||
self::assertSame(1, $code);
|
||||
self::assertFileDoesNotExist($this->expectedFile);
|
||||
}
|
||||
|
||||
public function testDiffShowsWhatChangedInAMirroredFunction(): void
|
||||
{
|
||||
file_put_contents(
|
||||
$this->themeDir . '/includes/builder/shortcode-core.php',
|
||||
"<?php\nfunction et_pb_submit_layout( \$args ) {\n\t\$a = 1;\n\treturn 2;\n}\n"
|
||||
);
|
||||
DiviReference::writeExpected(['library-submit-layout' => str_repeat('0', 64)], $this->expectedFile);
|
||||
DiviReference::writeSource(
|
||||
'library-submit-layout',
|
||||
"function et_pb_submit_layout( \$args ) {\n\t\$a = 1;\n\treturn 1;\n}",
|
||||
$this->sourceDir
|
||||
);
|
||||
|
||||
$this->command([CheckStep::MIRRORS => ['Bibliothek: Nachbau von et_pb_submit_layout() – Terme']])
|
||||
->run(['diff' => true]);
|
||||
|
||||
$output = implode("\n", $this->lines);
|
||||
self::assertStringContainsString('library-submit-layout', $output);
|
||||
self::assertStringContainsString("- \treturn 1;", $output);
|
||||
self::assertStringContainsString("+ \treturn 2;", $output);
|
||||
}
|
||||
|
||||
public function testUpdateReferenceWritesNothingWhenAMirrorIsUnreadable(): void
|
||||
{
|
||||
file_put_contents(
|
||||
$this->themeDir . '/includes/builder/shortcode-core.php',
|
||||
"<?php\nfunction et_pb_submit_layout( \$args ) {\n\treturn 2;\n}\n"
|
||||
);
|
||||
|
||||
$code = $this->command([CheckStep::MIRRORS => ['geändert']])->run(['update-reference' => true]);
|
||||
|
||||
// The other mirrored Divi files are missing in the temp theme.
|
||||
self::assertSame(1, $code);
|
||||
self::assertStringContainsString('nicht lesbar', implode("\n", $this->lines));
|
||||
self::assertFileDoesNotExist($this->expectedFile, 'all or nothing');
|
||||
}
|
||||
|
||||
public function testUpdateReferenceWritesFingerprintsAndSources(): void
|
||||
{
|
||||
$this->writeDivi();
|
||||
|
||||
$code = $this->command([CheckStep::MIRRORS => ['geändert']])->run(['update-reference' => true]);
|
||||
|
||||
self::assertSame(0, $code);
|
||||
self::assertSame(
|
||||
['library-submit-layout', 'tb-api-save', 'tb-load-setting-options', 'tb-store-template', 'vb-sync-flags'],
|
||||
array_keys(DiviReference::expected($this->expectedFile))
|
||||
);
|
||||
self::assertStringStartsWith(
|
||||
'function et_pb_submit_layout(',
|
||||
(string) DiviReference::readSource('library-submit-layout', $this->sourceDir)
|
||||
);
|
||||
}
|
||||
|
||||
/** Minimal stand-ins for the five mirrored Divi functions at their real paths. */
|
||||
private function writeDivi(): void
|
||||
{
|
||||
$files = [
|
||||
'includes/builder/shortcode-core.php' => "function et_pb_submit_layout( \$args ) {\n\treturn 1;\n}",
|
||||
'includes/builder/frontend-builder/theme-builder/api.php' => "function et_theme_builder_api_save() {\n}",
|
||||
'includes/builder/frontend-builder/theme-builder/theme-builder.php' =>
|
||||
"function et_theme_builder_store_template( \$a, \$b, \$c ) {\n}\n"
|
||||
. "function et_theme_builder_load_template_setting_options( \$ids ) {\n}",
|
||||
'includes/builder-5/server/VisualBuilder/REST/SyncToServer/SyncToServerController.php' =>
|
||||
"class SyncToServerController {\n\tpublic static function update( \$request ) {\n\t}\n}",
|
||||
];
|
||||
foreach ($files as $path => $code) {
|
||||
$file = $this->themeDir . '/' . $path;
|
||||
if (! is_dir(dirname($file))) {
|
||||
mkdir(dirname($file), 0777, true);
|
||||
}
|
||||
file_put_contents($file, "<?php\n" . $code . "\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user