From 20f360754db2fd3c9452b5b66688287ba73934d0 Mon Sep 17 00:00:00 2001 From: Sebastian Mendel Date: Mon, 8 Dec 2025 14:32:02 +0100 Subject: [PATCH 1/4] [BUGFIX] Improve error handling for invalid guides.xml configuration Instead of crashing with a PHP Fatal error when guides.xml contains invalid configuration (e.g., using element instead of theme="..." attribute), the guides entrypoint now catches InvalidTypeException and InvalidConfigurationException and displays a helpful error message. The message includes: - The actual configuration error - Common causes of the error - A correct format example - Suggestion to run lint-guides-xml for detailed validation Resolves the confusing "Expected scalar, but got array" fatal error that users encounter with malformed guides.xml files. --- bin/guides | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/bin/guides b/bin/guides index ae0906f82..75502991c 100644 --- a/bin/guides +++ b/bin/guides @@ -1,7 +1,30 @@ #!/usr/bin/env php getMessage() . "\033[0m\n"); + fwrite(STDERR, "\n"); + fwrite(STDERR, "\033[32mCommon causes:\033[0m\n"); + fwrite(STDERR, " - Invalid or unknown XML element\n"); + fwrite(STDERR, " - Missing required attributes\n"); + fwrite(STDERR, " - Invalid attribute values or types\n"); + fwrite(STDERR, "\n"); + fwrite(STDERR, "Run \033[33mvendor/bin/typo3-guides lint-guides-xml\033[0m for detailed validation.\n"); + fwrite(STDERR, "See: https://docs.typo3.org/m/typo3/docs-how-to-document/main/en-us/GeneralConventions/GuideXml.html\n"); + fwrite(STDERR, "\n"); + exit(1); +} From 0cc8b422e99b77ff2ead046ca33a2b87d80c8a82 Mon Sep 17 00:00:00 2001 From: Sebastian Mendel Date: Mon, 8 Dec 2025 15:03:47 +0100 Subject: [PATCH 2/4] Add integration tests for invalid guides.xml error handling --- tests/Integration/InvalidGuidesXmlTest.php | 96 +++++++++++++++++++ .../tests/invalid-guides-xml/input/Index.rst | 5 + .../tests/invalid-guides-xml/input/guides.xml | 5 + 3 files changed, 106 insertions(+) create mode 100644 tests/Integration/InvalidGuidesXmlTest.php create mode 100644 tests/Integration/tests/invalid-guides-xml/input/Index.rst create mode 100644 tests/Integration/tests/invalid-guides-xml/input/guides.xml diff --git a/tests/Integration/InvalidGuidesXmlTest.php b/tests/Integration/InvalidGuidesXmlTest.php new file mode 100644 index 000000000..7c4da4a81 --- /dev/null +++ b/tests/Integration/InvalidGuidesXmlTest.php @@ -0,0 +1,96 @@ +run(); + + // Should fail with exit code 1, not crash with fatal error + self::assertSame(1, $process->getExitCode(), 'Expected exit code 1 for invalid guides.xml'); + + $stderr = $process->getErrorOutput(); + + // Should contain helpful error message, not PHP fatal error + self::assertStringContainsString('Invalid guides.xml configuration', $stderr); + self::assertStringNotContainsString('PHP Fatal error', $stderr); + self::assertStringNotContainsString('Stack trace', $stderr); + + // Should reference documentation + self::assertStringContainsString('https://docs.typo3.org', $stderr); + } + + public function testInvalidGuidesXmlShowsCommonCauses(): void + { + $binPath = dirname(__DIR__, 2) . '/bin/guides'; + + $process = new Process([ + 'php', + $binPath, + 'run', + '--config=' . self::FIXTURES_PATH, + self::FIXTURES_PATH, + ]); + + $process->run(); + + $stderr = $process->getErrorOutput(); + + // Should show common causes section + self::assertStringContainsString('Common causes', $stderr); + } + + public function testValidGuidesXmlRendersSuccessfully(): void + { + $binPath = dirname(__DIR__, 2) . '/bin/guides'; + $validFixturePath = __DIR__ . '/tests/getting-started/input'; + + // Skip if fixture doesn't exist + if (!is_dir($validFixturePath)) { + self::markTestSkipped('Valid fixture not available'); + } + + $outputPath = sys_get_temp_dir() . '/render-guides-test-' . uniqid(); + + $process = new Process([ + 'php', + $binPath, + 'run', + '--config=' . $validFixturePath, + '--output=' . $outputPath, + $validFixturePath, + ]); + + $process->run(); + + // Clean up + if (is_dir($outputPath)) { + system('rm -rf ' . escapeshellarg($outputPath)); + } + + // Should succeed + self::assertSame(0, $process->getExitCode(), 'Expected exit code 0 for valid guides.xml. Error: ' . $process->getErrorOutput()); + } +} diff --git a/tests/Integration/tests/invalid-guides-xml/input/Index.rst b/tests/Integration/tests/invalid-guides-xml/input/Index.rst new file mode 100644 index 000000000..50a726c9d --- /dev/null +++ b/tests/Integration/tests/invalid-guides-xml/input/Index.rst @@ -0,0 +1,5 @@ +===== +Test +===== + +This should not render due to invalid guides.xml. diff --git a/tests/Integration/tests/invalid-guides-xml/input/guides.xml b/tests/Integration/tests/invalid-guides-xml/input/guides.xml new file mode 100644 index 000000000..88cc4c732 --- /dev/null +++ b/tests/Integration/tests/invalid-guides-xml/input/guides.xml @@ -0,0 +1,5 @@ + + + + + From 6266afb0e9e5b2f88daf2ca48121ddb631bbc310 Mon Sep 17 00:00:00 2001 From: Sebastian Mendel Date: Mon, 8 Dec 2025 15:16:04 +0100 Subject: [PATCH 3/4] Fix CI: move test fixture to avoid lint-guides-xml and data provider conflicts --- tests/Integration/InvalidGuidesXmlTest.php | 32 ++++++++++++++++--- .../invalid-guides-xml}/Index.rst | 0 .../invalid-guides-xml/guides.xml.fixture} | 0 3 files changed, 27 insertions(+), 5 deletions(-) rename tests/{Integration/tests/invalid-guides-xml/input => fixtures/invalid-guides-xml}/Index.rst (100%) rename tests/{Integration/tests/invalid-guides-xml/input/guides.xml => fixtures/invalid-guides-xml/guides.xml.fixture} (100%) diff --git a/tests/Integration/InvalidGuidesXmlTest.php b/tests/Integration/InvalidGuidesXmlTest.php index 7c4da4a81..1f3130c8d 100644 --- a/tests/Integration/InvalidGuidesXmlTest.php +++ b/tests/Integration/InvalidGuidesXmlTest.php @@ -9,10 +9,32 @@ /** * Tests error handling for invalid guides.xml configurations. + * + * The fixture is stored as guides.xml.fixture to avoid being picked up by lint-guides-xml. + * Tests copy it to a temp directory with the correct name before execution. */ final class InvalidGuidesXmlTest extends TestCase { - private const FIXTURES_PATH = __DIR__ . '/tests/invalid-guides-xml/input'; + private const FIXTURE_SOURCE = __DIR__ . '/../fixtures/invalid-guides-xml'; + + private string $tempDir = ''; + + protected function setUp(): void + { + $this->tempDir = sys_get_temp_dir() . '/render-guides-invalid-test-' . uniqid(); + mkdir($this->tempDir, 0755, true); + + // Copy fixture files to temp directory + copy(self::FIXTURE_SOURCE . '/guides.xml.fixture', $this->tempDir . '/guides.xml'); + copy(self::FIXTURE_SOURCE . '/Index.rst', $this->tempDir . '/Index.rst'); + } + + protected function tearDown(): void + { + if (is_dir($this->tempDir)) { + system('rm -rf ' . escapeshellarg($this->tempDir)); + } + } public function testInvalidGuidesXmlShowsHelpfulErrorMessage(): void { @@ -22,8 +44,8 @@ public function testInvalidGuidesXmlShowsHelpfulErrorMessage(): void 'php', $binPath, 'run', - '--config=' . self::FIXTURES_PATH, - self::FIXTURES_PATH, + '--config=' . $this->tempDir, + $this->tempDir, ]); $process->run(); @@ -50,8 +72,8 @@ public function testInvalidGuidesXmlShowsCommonCauses(): void 'php', $binPath, 'run', - '--config=' . self::FIXTURES_PATH, - self::FIXTURES_PATH, + '--config=' . $this->tempDir, + $this->tempDir, ]); $process->run(); diff --git a/tests/Integration/tests/invalid-guides-xml/input/Index.rst b/tests/fixtures/invalid-guides-xml/Index.rst similarity index 100% rename from tests/Integration/tests/invalid-guides-xml/input/Index.rst rename to tests/fixtures/invalid-guides-xml/Index.rst diff --git a/tests/Integration/tests/invalid-guides-xml/input/guides.xml b/tests/fixtures/invalid-guides-xml/guides.xml.fixture similarity index 100% rename from tests/Integration/tests/invalid-guides-xml/input/guides.xml rename to tests/fixtures/invalid-guides-xml/guides.xml.fixture From 70862af615be035e26c663317a4f66e6a1ccfcc0 Mon Sep 17 00:00:00 2001 From: Sebastian Mendel Date: Tue, 9 Dec 2025 08:42:20 +0100 Subject: [PATCH 4/4] [TASK] Fix CGL: use explicit octal notation for mkdir permission --- tests/Integration/InvalidGuidesXmlTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Integration/InvalidGuidesXmlTest.php b/tests/Integration/InvalidGuidesXmlTest.php index 1f3130c8d..67df08128 100644 --- a/tests/Integration/InvalidGuidesXmlTest.php +++ b/tests/Integration/InvalidGuidesXmlTest.php @@ -22,7 +22,7 @@ final class InvalidGuidesXmlTest extends TestCase protected function setUp(): void { $this->tempDir = sys_get_temp_dir() . '/render-guides-invalid-test-' . uniqid(); - mkdir($this->tempDir, 0755, true); + mkdir($this->tempDir, 0o755, true); // Copy fixture files to temp directory copy(self::FIXTURE_SOURCE . '/guides.xml.fixture', $this->tempDir . '/guides.xml');