Skip to content

Commit 6a83bc1

Browse files
committed
4.0 | Generators/Generator: improve error messages
Make errors encountered when processing XML documentation more informative by providing more specific error messages via a dedicated `GeneratorException`, which extends the PHP native `DomainException`. Ref: * https://www.php.net/class.domainexception
1 parent 492b884 commit 6a83bc1

File tree

7 files changed

+108
-16
lines changed

7 files changed

+108
-16
lines changed

src/Exceptions/GeneratorException.php

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
/**
3+
* An exception thrown by PHP_CodeSniffer when it encounters an error in the XML document being processed
4+
* by one of the documentation Generators.
5+
*
6+
* @author Juliette Reinders Folmer <[email protected]>
7+
* @copyright 2024 PHPCSStandards and contributors
8+
* @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
9+
*/
10+
11+
namespace PHP_CodeSniffer\Exceptions;
12+
13+
use DomainException;
14+
15+
class GeneratorException extends DomainException
16+
{
17+
18+
}//end class

src/Generators/Generator.php

+11
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,10 @@
1515
namespace PHP_CodeSniffer\Generators;
1616

1717
use DOMDocument;
18+
use DOMElement;
1819
use DOMNode;
1920
use PHP_CodeSniffer\Autoload;
21+
use PHP_CodeSniffer\Exceptions\GeneratorException;
2022
use PHP_CodeSniffer\Ruleset;
2123

2224
abstract class Generator
@@ -112,13 +114,22 @@ protected function getTitle(DOMNode $doc)
112114
*
113115
* @return void
114116
* @see processSniff()
117+
*
118+
* @throws \PHP_CodeSniffer\Exceptions\GeneratorException If there is no <documentation> element
119+
* in the XML document.
115120
*/
116121
public function generate()
117122
{
118123
foreach ($this->docFiles as $file) {
119124
$doc = new DOMDocument();
120125
$doc->load($file);
121126
$documentation = $doc->getElementsByTagName('documentation')->item(0);
127+
if (($documentation instanceof DOMNode) === false) {
128+
throw new GeneratorException(
129+
'Missing top-level <documentation> element in XML documentation file '.$file
130+
);
131+
}
132+
122133
$this->processSniff($documentation);
123134
}
124135

src/Generators/HTML.php

+15-3
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
use DOMElement;
2020
use DOMNode;
2121
use PHP_CodeSniffer\Config;
22+
use PHP_CodeSniffer\Exceptions\GeneratorException;
2223

2324
class HTML extends Generator
2425
{
@@ -126,6 +127,9 @@ class HTML extends Generator
126127
*
127128
* @return void
128129
* @see processSniff()
130+
*
131+
* @throws \PHP_CodeSniffer\Exceptions\GeneratorException If there is no <documentation> element
132+
* in the XML document.
129133
*/
130134
public function generate()
131135
{
@@ -134,10 +138,18 @@ public function generate()
134138
}
135139

136140
ob_start();
137-
parent::generate();
141+
try {
142+
parent::generate();
143+
$content = ob_get_clean();
144+
} catch (GeneratorException $e) {
145+
ob_end_clean();
146+
$content = '';
147+
}
138148

139-
$content = ob_get_contents();
140-
ob_end_clean();
149+
// If an exception was caught, rethrow it outside of the output buffer.
150+
if (isset($e) === true) {
151+
throw $e;
152+
}
141153

142154
// Clear anchor cache after Documentation generation.
143155
// The anchor generation for the TOC anchor links will use the same logic, so should end up with the same unique slugs.

src/Generators/Markdown.php

+15-3
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
use DOMElement;
1515
use DOMNode;
1616
use PHP_CodeSniffer\Config;
17+
use PHP_CodeSniffer\Exceptions\GeneratorException;
1718

1819
class Markdown extends Generator
1920
{
@@ -24,6 +25,9 @@ class Markdown extends Generator
2425
*
2526
* @return void
2627
* @see processSniff()
28+
*
29+
* @throws \PHP_CodeSniffer\Exceptions\GeneratorException If there is no <documentation> element
30+
* in the XML document.
2731
*/
2832
public function generate()
2933
{
@@ -32,10 +36,18 @@ public function generate()
3236
}
3337

3438
ob_start();
35-
parent::generate();
39+
try {
40+
parent::generate();
41+
$content = ob_get_clean();
42+
} catch (GeneratorException $e) {
43+
ob_end_clean();
44+
$content = '';
45+
}
3646

37-
$content = ob_get_contents();
38-
ob_end_clean();
47+
// If an exception was caught, rethrow it outside of the output buffer.
48+
if (isset($e) === true) {
49+
throw $e;
50+
}
3951

4052
if (trim($content) !== '') {
4153
echo $this->getFormattedHeader();

tests/Core/Generators/GeneratorTest.php

+3-10
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
namespace PHP_CodeSniffer\Tests\Core\Generators;
1010

11+
use PHP_CodeSniffer\Exceptions\GeneratorException;
1112
use PHP_CodeSniffer\Ruleset;
1213
use PHP_CodeSniffer\Tests\ConfigDouble;
1314
use PHP_CodeSniffer\Tests\Core\Generators\Fixtures\MockGenerator;
@@ -94,8 +95,6 @@ public static function dataConstructor()
9495
/**
9596
* Verify that an XML doc which isn't valid documentation yields an Exception to warn devs.
9697
*
97-
* This should not be hidden via defensive coding!
98-
*
9998
* @return void
10099
*/
101100
public function testGeneratingInvalidDocsResultsInException()
@@ -105,14 +104,8 @@ public function testGeneratingInvalidDocsResultsInException()
105104
$config = new ConfigDouble(["--standard=$standard"]);
106105
$ruleset = new Ruleset($config);
107106

108-
if (PHP_VERSION_ID >= 80000) {
109-
$message = 'processSniff(): Argument #1 ($doc) must be of type DOMNode, null given';
110-
} else {
111-
$message = 'processSniff() must be an instance of DOMNode, null given';
112-
}
113-
114-
$this->expectException('TypeError');
115-
$this->expectExceptionMessage($message);
107+
$this->expectException(GeneratorException::class);
108+
$this->expectExceptionMessage('Missing top-level <documentation> element in XML documentation file');
116109

117110
$generator = new MockGenerator($ruleset);
118111
$generator->generate();

tests/Core/Generators/HTMLTest.php

+23
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
namespace PHP_CodeSniffer\Tests\Core\Generators;
1010

11+
use PHP_CodeSniffer\Exceptions\GeneratorException;
12+
use PHP_CodeSniffer\Generators\HTML;
1113
use PHP_CodeSniffer\Ruleset;
1214
use PHP_CodeSniffer\Tests\ConfigDouble;
1315
use PHP_CodeSniffer\Tests\Core\Generators\Fixtures\HTMLDouble;
@@ -23,6 +25,27 @@ final class HTMLTest extends TestCase
2325
{
2426

2527

28+
/**
29+
* Verify that an XML doc which isn't valid documentation yields an Exception to warn devs.
30+
*
31+
* @return void
32+
*/
33+
public function testGeneratingInvalidDocsResultsInException()
34+
{
35+
// Set up the ruleset.
36+
$standard = __DIR__.'/NoValidDocsTest.xml';
37+
$config = new ConfigDouble(["--standard=$standard"]);
38+
$ruleset = new Ruleset($config);
39+
40+
$this->expectException(GeneratorException::class);
41+
$this->expectExceptionMessage('Missing top-level <documentation> element in XML documentation file');
42+
43+
$generator = new HTML($ruleset);
44+
$generator->generate();
45+
46+
}//end testGeneratingInvalidDocsResultsInException()
47+
48+
2649
/**
2750
* Test the generated docs.
2851
*

tests/Core/Generators/MarkdownTest.php

+23
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
namespace PHP_CodeSniffer\Tests\Core\Generators;
1010

11+
use PHP_CodeSniffer\Exceptions\GeneratorException;
12+
use PHP_CodeSniffer\Generators\Markdown;
1113
use PHP_CodeSniffer\Ruleset;
1214
use PHP_CodeSniffer\Tests\ConfigDouble;
1315
use PHP_CodeSniffer\Tests\Core\Generators\Fixtures\MarkdownDouble;
@@ -23,6 +25,27 @@ final class MarkdownTest extends TestCase
2325
{
2426

2527

28+
/**
29+
* Verify that an XML doc which isn't valid documentation yields an Exception to warn devs.
30+
*
31+
* @return void
32+
*/
33+
public function testGeneratingInvalidDocsResultsInException()
34+
{
35+
// Set up the ruleset.
36+
$standard = __DIR__.'/NoValidDocsTest.xml';
37+
$config = new ConfigDouble(["--standard=$standard"]);
38+
$ruleset = new Ruleset($config);
39+
40+
$this->expectException(GeneratorException::class);
41+
$this->expectExceptionMessage('Missing top-level <documentation> element in XML documentation file');
42+
43+
$generator = new Markdown($ruleset);
44+
$generator->generate();
45+
46+
}//end testGeneratingInvalidDocsResultsInException()
47+
48+
2649
/**
2750
* Test the generated docs.
2851
*

0 commit comments

Comments
 (0)