Skip to content

Commit 830b4af

Browse files
Merge branch '12.5' into 13.1
* 12.5: Reject invalid class and method names
2 parents 05c9347 + 05489e9 commit 830b4af

7 files changed

Lines changed: 67 additions & 3 deletions

File tree

ChangeLog-13.1.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ All notable changes of the PHPUnit 13.1 release series are documented in this fi
77
### Fixed
88

99
* [#6595](https://github.com/sebastianbergmann/phpunit/issues/6595): Crash when before-class or after-class method fails with assertion failure
10+
* `MockBuilder::setMockClassName()` and `TestStubBuilder::setStubClassName()` now reject values that are not valid unqualified PHP class identifiers, throwing the new `InvalidClassNameException`
11+
* The regular expression used by `Generator::ensureValidMethods()` to validate method names passed to `MockBuilder::onlyMethods()` and `addMethods()` was not anchored, so any string containing a valid identifier substring (including strings with parentheses, braces, comments, or newlines) was accepted
1012

1113
## [13.1.7] - 2026-04-18
1214

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php declare(strict_types=1);
2+
/*
3+
* This file is part of PHPUnit.
4+
*
5+
* (c) Sebastian Bergmann <sebastian@phpunit.de>
6+
*
7+
* For the full copyright and license information, please view the LICENSE
8+
* file that was distributed with this source code.
9+
*/
10+
namespace PHPUnit\Framework\MockObject\Generator;
11+
12+
use function sprintf;
13+
14+
/**
15+
* @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
16+
*
17+
* @internal This class is not covered by the backward compatibility promise for PHPUnit
18+
*/
19+
final class InvalidClassNameException extends \PHPUnit\Framework\Exception implements Exception
20+
{
21+
public function __construct(string $className)
22+
{
23+
parent::__construct(
24+
sprintf(
25+
'Cannot use "%s" as the name of a test double class because it is not a valid PHP class name',
26+
$className,
27+
),
28+
);
29+
}
30+
}

src/Framework/MockObject/Generator/Generator.php

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ final class Generator
8383
* @throws ClassIsEnumerationException
8484
* @throws ClassIsFinalException
8585
* @throws DuplicateMethodException
86+
* @throws InvalidClassNameException
8687
* @throws InvalidMethodNameException
8788
* @throws NameAlreadyInUseException
8889
* @throws ReflectionException
@@ -97,6 +98,7 @@ public function testDouble(string $type, bool $mockObject, ?array $methods = [],
9798

9899
$this->ensureKnownType($type);
99100
$this->ensureValidMethods($methods);
101+
$this->ensureValidNameForTestDoubleClass($mockClassName);
100102
$this->ensureNameForTestDoubleClassIsAvailable($mockClassName);
101103

102104
$mock = $this->generate(
@@ -688,7 +690,7 @@ private function ensureValidMethods(?array $methods): void
688690
}
689691

690692
foreach ($methods as $method) {
691-
if (!preg_match('~[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*~', (string) $method)) {
693+
if (!preg_match('~\A[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*\z~', (string) $method)) {
692694
throw new InvalidMethodNameException((string) $method);
693695
}
694696
}
@@ -698,6 +700,20 @@ private function ensureValidMethods(?array $methods): void
698700
}
699701
}
700702

703+
/**
704+
* @throws InvalidClassNameException
705+
*/
706+
private function ensureValidNameForTestDoubleClass(string $className): void
707+
{
708+
if ($className === '') {
709+
return;
710+
}
711+
712+
if (!preg_match('~\A[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*\z~', $className)) {
713+
throw new InvalidClassNameException($className);
714+
}
715+
}
716+
701717
/**
702718
* @throws NameAlreadyInUseException
703719
* @throws ReflectionException

src/Framework/MockObject/MockBuilder.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
use PHPUnit\Framework\MockObject\Generator\ClassIsEnumerationException;
1515
use PHPUnit\Framework\MockObject\Generator\ClassIsFinalException;
1616
use PHPUnit\Framework\MockObject\Generator\DuplicateMethodException;
17+
use PHPUnit\Framework\MockObject\Generator\InvalidClassNameException;
1718
use PHPUnit\Framework\MockObject\Generator\InvalidMethodNameException;
1819
use PHPUnit\Framework\MockObject\Generator\NameAlreadyInUseException;
1920
use PHPUnit\Framework\MockObject\Generator\ReflectionException;
@@ -52,6 +53,7 @@ public function __construct(TestCase $testCase, string $type)
5253
* @throws ClassIsFinalException
5354
* @throws DuplicateMethodException
5455
* @throws InvalidArgumentException
56+
* @throws InvalidClassNameException
5557
* @throws InvalidMethodNameException
5658
* @throws NameAlreadyInUseException
5759
* @throws ReflectionException

src/Framework/MockObject/TestStubBuilder.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
use PHPUnit\Framework\MockObject\Generator\ClassIsEnumerationException;
1414
use PHPUnit\Framework\MockObject\Generator\ClassIsFinalException;
1515
use PHPUnit\Framework\MockObject\Generator\DuplicateMethodException;
16+
use PHPUnit\Framework\MockObject\Generator\InvalidClassNameException;
1617
use PHPUnit\Framework\MockObject\Generator\InvalidMethodNameException;
1718
use PHPUnit\Framework\MockObject\Generator\NameAlreadyInUseException;
1819
use PHPUnit\Framework\MockObject\Generator\ReflectionException;
@@ -37,6 +38,7 @@ final class TestStubBuilder extends TestDoubleBuilder
3738
* @throws ClassIsEnumerationException
3839
* @throws ClassIsFinalException
3940
* @throws DuplicateMethodException
41+
* @throws InvalidClassNameException
4042
* @throws InvalidMethodNameException
4143
* @throws NameAlreadyInUseException
4244
* @throws ReflectionException

tests/unit/Framework/MockObject/Creation/MockBuilderTest.php

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
use PHPUnit\Framework\Attributes\Medium;
1818
use PHPUnit\Framework\Attributes\TestDox;
1919
use PHPUnit\Framework\MockObject\Generator\DuplicateMethodException;
20+
use PHPUnit\Framework\MockObject\Generator\InvalidClassNameException;
2021
use PHPUnit\Framework\MockObject\Generator\InvalidMethodNameException;
2122
use PHPUnit\Framework\MockObject\Generator\NameAlreadyInUseException;
2223
use PHPUnit\Framework\TestCase;
@@ -28,6 +29,7 @@
2829
#[CoversClass(MockBuilder::class)]
2930
#[CoversMethod(TestCase::class, 'getMockBuilder')]
3031
#[CoversClass(DuplicateMethodException::class)]
32+
#[CoversClass(InvalidClassNameException::class)]
3133
#[CoversClass(InvalidMethodNameException::class)]
3234
#[CoversClass(NameAlreadyInUseException::class)]
3335
#[Group('test-doubles')]
@@ -54,7 +56,17 @@ public function testCannotCreateMockObjectWithSpecifiedClassNameWhenClassWithTha
5456
$this->expectException(NameAlreadyInUseException::class);
5557

5658
$this->getMockBuilder(InterfaceWithReturnTypeDeclaration::class)
57-
->setMockClassName(__CLASS__)
59+
->setMockClassName('stdClass')
60+
->getMock();
61+
}
62+
63+
#[TestDox('setMockClassName() rejects values that are not valid PHP class names')]
64+
public function testCannotCreateMockObjectWithInvalidClassName(): void
65+
{
66+
$this->expectException(InvalidClassNameException::class);
67+
68+
$this->getMockBuilder(InterfaceWithReturnTypeDeclaration::class)
69+
->setMockClassName("Foo {} ?>\n<?php class Bar")
5870
->getMock();
5971
}
6072

tests/unit/Framework/MockObject/Creation/TestStubBuilderTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ public function testCannotCreateTestStubWithSpecifiedClassNameWhenClassWithThatN
4949
$this->expectException(NameAlreadyInUseException::class);
5050

5151
$this->getStubBuilder(InterfaceWithReturnTypeDeclaration::class)
52-
->setStubClassName(__CLASS__)
52+
->setStubClassName('stdClass')
5353
->getStub();
5454
}
5555

0 commit comments

Comments
 (0)