Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 25 additions & 2 deletions bin/guides
Original file line number Diff line number Diff line change
@@ -1,7 +1,30 @@
#!/usr/bin/env php
<?php

declare(strict_types=1);

use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
use Symfony\Component\Config\Definition\Exception\InvalidTypeException;

$root = dirname(__DIR__);

require_once $root . '/vendor/autoload.php';
require_once $root . '/vendor/phpdocumentor/guides-cli/bin/guides';
require_once $root . '/vendor/autoload.php';

try {
require_once $root . '/vendor/phpdocumentor/guides-cli/bin/guides';
} catch (InvalidTypeException|InvalidConfigurationException $e) {
fwrite(STDERR, "\033[37;41m Invalid guides.xml configuration \033[0m\n");
fwrite(STDERR, "\n");
fwrite(STDERR, "Your guides.xml file contains a configuration error:\n");
fwrite(STDERR, " \033[33m" . $e->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);
}
118 changes: 118 additions & 0 deletions tests/Integration/InvalidGuidesXmlTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
<?php

declare(strict_types=1);

namespace T3Docs\Typo3DocsTheme\Integration;

use PHPUnit\Framework\TestCase;
use Symfony\Component\Process\Process;

/**
* 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 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, 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());
}
}
5 changes: 5 additions & 0 deletions tests/fixtures/invalid-guides-xml/Index.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
=====
Test
=====

This should not render due to invalid guides.xml.
5 changes: 5 additions & 0 deletions tests/fixtures/invalid-guides-xml/guides.xml.fixture
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<guides xmlns="https://www.phpdoc.org/guides">
<theme name="typo3docs" />
<project title="Test" />
</guides>