Skip to content

Commit

Permalink
Handle invalid version requirements in annotations by ignoring them a…
Browse files Browse the repository at this point in the history
…nd emitting a warning instead of crashing
  • Loading branch information
sebastianbergmann committed Apr 29, 2024
1 parent f251c09 commit 3ce3114
Show file tree
Hide file tree
Showing 5 changed files with 135 additions and 14 deletions.
2 changes: 2 additions & 0 deletions src/Metadata/Parser/Annotation/DocBlock.php
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,8 @@ private function __construct(string $docComment, array $symbolAnnotations, int $
* string,
* string|array{version: string, operator: string}|array{constraint: string}|array<int|string, string>
* >
*
* @throws InvalidVersionRequirementException
*/
public function requirements(): array
{
Expand Down
52 changes: 38 additions & 14 deletions src/Metadata/Parser/AnnotationParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,16 @@
use function method_exists;
use function preg_replace;
use function rtrim;
use function sprintf;
use function str_contains;
use function str_starts_with;
use function strlen;
use function substr;
use function trim;
use PHPUnit\Event\Facade as EventFacade;
use PHPUnit\Metadata\Annotation\Parser\Registry as AnnotationRegistry;
use PHPUnit\Metadata\AnnotationsAreNotSupportedForInternalClassesException;
use PHPUnit\Metadata\InvalidVersionRequirementException;
use PHPUnit\Metadata\Metadata;
use PHPUnit\Metadata\MetadataCollection;
use PHPUnit\Metadata\ReflectionException;
Expand Down Expand Up @@ -147,13 +150,23 @@ public function forClass(string $className): MetadataCollection
}
}

$result = array_merge(
$result,
$this->parseRequirements(
AnnotationRegistry::getInstance()->forClassName($className)->requirements(),
'class',
),
);
try {
$result = array_merge(
$result,
$this->parseRequirements(
AnnotationRegistry::getInstance()->forClassName($className)->requirements(),
'class',
),
);
} catch (InvalidVersionRequirementException $e) {
EventFacade::emitter()->testRunnerTriggeredWarning(
sprintf(
'Class %s is annotated using an invalid version requirement: %s',
$className,
$e->getMessage(),
),
);
}

return MetadataCollection::fromArray($result);
}
Expand Down Expand Up @@ -364,13 +377,24 @@ public function forMethod(string $className, string $methodName): MetadataCollec
}

if (method_exists($className, $methodName)) {
$result = array_merge(
$result,
$this->parseRequirements(
AnnotationRegistry::getInstance()->forMethod($className, $methodName)->requirements(),
'method',
),
);
try {
$result = array_merge(
$result,
$this->parseRequirements(
AnnotationRegistry::getInstance()->forMethod($className, $methodName)->requirements(),
'method',
),
);
} catch (InvalidVersionRequirementException $e) {
EventFacade::emitter()->testRunnerTriggeredWarning(
sprintf(
'Method %s::%s is annotated using an invalid version requirement: %s',
$className,
$methodName,
$e->getMessage(),
),
);
}
}

return MetadataCollection::fromArray($result);
Expand Down
26 changes: 26 additions & 0 deletions tests/_files/InvalidRequirementsTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\TestFixture;

use PHPUnit\Framework\TestCase;

/**
* @requires PHP ~~9.0
*/
final class InvalidRequirementsTest extends TestCase
{
/**
* @requires PHP ~~9.0
*/
public function testInvalidVersionConstraint(): void
{
$this->assertTrue(true);
}
}
28 changes: 28 additions & 0 deletions tests/end-to-end/generic/invalid-requirements.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
--TEST--
phpunit --no-configuration ../_files/InvalidRequirementsTest.php
--FILE--
<?php declare(strict_types=1);
require_once(__DIR__ . '/../../bootstrap.php');

$_SERVER['argv'][] = '--do-not-cache-result';
$_SERVER['argv'][] = '--no-configuration';
$_SERVER['argv'][] = \realpath(__DIR__ . '/../../_files/InvalidRequirementsTest.php');

(new PHPUnit\TextUI\Application)->run($_SERVER['argv']);
--EXPECTF--
PHPUnit %s by Sebastian Bergmann and contributors.

Runtime: %s

. 1 / 1 (100%)

Time: %s, Memory: %s

There were 2 PHPUnit test runner warnings:

1) Method PHPUnit\TestFixture\InvalidRequirementsTest::testInvalidVersionConstraint is annotated using an invalid version requirement: Version constraint ~~9.0 is not supported.

2) Class PHPUnit\TestFixture\InvalidRequirementsTest is annotated using an invalid version requirement: Version constraint ~~9.0 is not supported.

WARNINGS!
Tests: 1, Assertions: 1, Warnings: 2.
41 changes: 41 additions & 0 deletions tests/unit/Metadata/Parser/Annotation/DocBlockTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Metadata\Annotation;

use Exception;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\Group;
use PHPUnit\Framework\Attributes\Small;
use PHPUnit\Framework\TestCase;
use PHPUnit\Metadata\Annotation\Parser\DocBlock;
use PHPUnit\Metadata\AnnotationsAreNotSupportedForInternalClassesException;
use ReflectionClass;
use ReflectionMethod;

#[CoversClass(DocBlock::class)]
#[Small]
#[Group('metadata')]
#[Group('metadata/annotations')]
final class DocBlockTest extends TestCase
{
public function testDoesNotSupportInternalClasses(): void
{
$this->expectException(AnnotationsAreNotSupportedForInternalClassesException::class);

DocBlock::ofClass(new ReflectionClass(Exception::class));
}

public function testDoesNotSupportInternalMethods(): void
{
$this->expectException(AnnotationsAreNotSupportedForInternalClassesException::class);

DocBlock::ofMethod(new ReflectionMethod(Exception::class, 'getMessage'));
}
}

0 comments on commit 3ce3114

Please sign in to comment.