refactor: ColumnWidths holds the column-width rules (H5)

Composer::row uses ColumnWidths::parse; rowWidthsError and its error-state
save/restore are gone. The update width check moves out of
DiviUpdateAbility into ColumnWidths::updateErrors. Behaviour unchanged.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01At3V6SjwbMe6eMzVGW3Hs7
This commit is contained in:
2026-09-26 18:21:03 +02:00
co-authored by Claude Opus 5.5
parent 6cf0a565e6
commit 9da236b0e3
5 changed files with 267 additions and 219 deletions
@@ -0,0 +1,43 @@
<?php
declare(strict_types=1);
namespace LIT\MCP\Tests\Unit\Integrations\Divi\Compose;
use LIT\MCP\Integrations\Divi\Compose\ColumnWidths;
use PHPUnit\Framework\TestCase;
final class ColumnWidthsTest extends TestCase
{
/** Ruling S41: column widths on update follow the rules of "columns". */
public function testRowWidthsAreChecked(): void
{
self::assertNull(ColumnWidths::rowError(['8_24', '16_24']));
self::assertNull(ColumnWidths::rowError(['1_5', '1_5', '1_5', '1_5', '1_5']));
self::assertNotNull(ColumnWidths::rowError(['12_24', '16_24']));
self::assertNotNull(ColumnWidths::rowError(['1_13', '12_13']));
self::assertNotNull(ColumnWidths::rowError(['x', '24_24']));
self::assertNotNull(ColumnWidths::rowError([]));
}
public function testParseTurnsFractionsIntoFlexTypes(): void
{
self::assertSame(['widths' => ['8_24', '16_24'], 'error' => null], ColumnWidths::parse('1_3, 2_3'));
self::assertSame(['24_24'], ColumnWidths::parse(42)['widths']);
self::assertStringContainsString('erwartet', (string) ColumnWidths::parse('abc')['error']);
self::assertStringContainsString('1_13', (string) ColumnWidths::parse('1_13,12_13')['error']);
self::assertStringContainsString('volle Zeile', (string) ColumnWidths::parse('1_2,1_3')['error']);
}
/** Ruling S43: the builder's column classes. */
public function testColumnClassesAreTheBuilderList(): void
{
foreach (['1_24', '24_24', '1_5', '3_5', '1_11', 'none'] as $class) {
self::assertTrue(ColumnWidths::isColumnClass($class), $class);
}
foreach (['0_24', '25_24', '1_2', '4_5', '1_13', '', null, 8] as $class) {
self::assertFalse(ColumnWidths::isColumnClass($class), var_export($class, true));
}
}
}
@@ -298,19 +298,6 @@ final class ComposerTest extends TestCase
self::assertSame('h3', $explicit['blocks'][0]->attrs()['title']['decoration']['font']['font']['desktop']['value']['headingLevel']);
}
/** Ruling S41: column widths on update follow the rules of "columns". */
public function testRowWidthsAreChecked(): void
{
$composer = ComposeFixture::composer();
self::assertNull($composer->rowWidthsError(['8_24', '16_24']));
self::assertNull($composer->rowWidthsError(['1_5', '1_5', '1_5', '1_5', '1_5']));
self::assertNotNull($composer->rowWidthsError(['12_24', '16_24']));
self::assertNotNull($composer->rowWidthsError(['1_13', '12_13']));
self::assertNotNull($composer->rowWidthsError(['x', '24_24']));
self::assertNotNull($composer->rowWidthsError([]));
}
/** Ruling S13: labels go through the choke point; a label that fails is an error, never stored raw. */
public function testLabelsAreCleanedOrReported(): void
{