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); +} diff --git a/tests/Integration/InvalidGuidesXmlTest.php b/tests/Integration/InvalidGuidesXmlTest.php new file mode 100644 index 000000000..67df08128 --- /dev/null +++ b/tests/Integration/InvalidGuidesXmlTest.php @@ -0,0 +1,118 @@ +tempDir = sys_get_temp_dir() . '/render-guides-invalid-test-' . uniqid(); + mkdir($this->tempDir, 0o755, 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 + { + $binPath = dirname(__DIR__, 2) . '/bin/guides'; + + $process = new Process([ + 'php', + $binPath, + 'run', + '--config=' . $this->tempDir, + $this->tempDir, + ]); + + $process->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=' . $this->tempDir, + $this->tempDir, + ]); + + $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/fixtures/invalid-guides-xml/Index.rst b/tests/fixtures/invalid-guides-xml/Index.rst new file mode 100644 index 000000000..50a726c9d --- /dev/null +++ b/tests/fixtures/invalid-guides-xml/Index.rst @@ -0,0 +1,5 @@ +===== +Test +===== + +This should not render due to invalid guides.xml. diff --git a/tests/fixtures/invalid-guides-xml/guides.xml.fixture b/tests/fixtures/invalid-guides-xml/guides.xml.fixture new file mode 100644 index 000000000..88cc4c732 --- /dev/null +++ b/tests/fixtures/invalid-guides-xml/guides.xml.fixture @@ -0,0 +1,5 @@ + + + + +