Skip to content

Commit 7b186c2

Browse files
committed
collect autoloading deprecations before running testCase
1 parent 3ef7e2b commit 7b186c2

File tree

9 files changed

+181
-0
lines changed

9 files changed

+181
-0
lines changed

src/Runner/ErrorHandler.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,11 @@ final class ErrorHandler
5959
private ?int $originalErrorReportingLevel = null;
6060
private readonly Source $source;
6161

62+
/**
63+
* @var list<array{int, string, string, int}>
64+
*/
65+
private array $globalDeprecations = [];
66+
6267
/**
6368
* @var ?array{functions: list<non-empty-string>, methods: list<array{className: class-string, methodName: non-empty-string}>}
6469
*/
@@ -197,6 +202,23 @@ public function __invoke(int $errorNumber, string $errorString, string $errorFil
197202
return false;
198203
}
199204

205+
public function deprecationHandler(int $errorNumber, string $errorString, string $errorFile, int $errorLine): bool
206+
{
207+
$this->globalDeprecations[] = [$errorNumber, $errorString, $errorFile, $errorLine];
208+
209+
return true;
210+
}
211+
212+
public function registerDeprecationHandler(): void
213+
{
214+
set_error_handler([self::$instance, 'deprecationHandler'], E_USER_DEPRECATED);
215+
}
216+
217+
public function restoreDeprecationHandler(): void
218+
{
219+
restore_error_handler();
220+
}
221+
200222
public function enable(): void
201223
{
202224
if ($this->enabled) {
@@ -213,6 +235,7 @@ public function enable(): void
213235

214236
$this->enabled = true;
215237
$this->originalErrorReportingLevel = error_reporting();
238+
$this->triggerGlobalDeprecations();
216239

217240
error_reporting($this->originalErrorReportingLevel & self::UNHANDLEABLE_LEVELS);
218241
}
@@ -422,4 +445,11 @@ private function stackTrace(): string
422445

423446
return $buffer;
424447
}
448+
449+
private function triggerGlobalDeprecations(): void
450+
{
451+
foreach ($this->globalDeprecations ?? [] as $d) {
452+
$this->__invoke(...$d);
453+
}
454+
}
425455
}

src/TextUI/Application.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,8 +178,12 @@ public function run(array $argv): int
178178

179179
EventFacade::instance()->seal();
180180

181+
ErrorHandler::instance()->registerDeprecationHandler();
182+
181183
$testSuite = $this->buildTestSuite($configuration);
182184

185+
ErrorHandler::instance()->restoreDeprecationHandler();
186+
183187
$this->executeCommandsThatRequireTheTestSuite($configuration, $cliConfiguration, $testSuite);
184188

185189
if ($testSuite->isEmpty() && !$configuration->hasCliArguments() && $configuration->testSuite()->isEmpty()) {
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:noNamespaceSchemaLocation="../../../../../phpunit.xsd"
4+
bootstrap="vendor/autoload.php"
5+
>
6+
<testsuites>
7+
<testsuite name="default">
8+
<directory>tests</directory>
9+
</testsuite>
10+
</testsuites>
11+
12+
<source>
13+
<include>
14+
<directory>src</directory>
15+
</include>
16+
</source>
17+
</phpunit>
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
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\TestFixture\SelfDirectIndirect;
11+
12+
final class FirstPartyClass
13+
{
14+
public function method(): true
15+
{
16+
return ThirdPartyClass::A;
17+
}
18+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
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\TestFixture\SelfDirectIndirect;
11+
12+
use PHPUnit\Framework\TestCase;
13+
14+
final class FirstPartyClassTest extends TestCase
15+
{
16+
public function testOne(): void
17+
{
18+
$this->assertTrue((new FirstPartyClass)->method());
19+
}
20+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?php declare(strict_types=1);
2+
namespace PHPUnit\TestFixture\SelfDirectIndirect;
3+
4+
@trigger_error('This class is deprecated', E_USER_DEPRECATED);
5+
6+
final class ThirdPartyClass
7+
{
8+
const A = true;
9+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?php declare(strict_types=1);
2+
3+
spl_autoload_register(function ($class) {
4+
$parts = explode('\\', $class);
5+
$file = end($parts) . '.php';
6+
7+
match ($file) {
8+
'FirstPartyClass.php' => require __DIR__ . '/../src/' . $file,
9+
'ThirdPartyClass.php' => require __DIR__ . '/' . $file,
10+
default => throw new LogicException
11+
};
12+
});
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
--TEST--
2+
The right events are emitted in the right order for a test that loads a class that triggers E_USER_DEPRECATED
3+
--FILE--
4+
<?php declare(strict_types=1);
5+
$_SERVER['argv'][] = '--do-not-cache-result';
6+
$_SERVER['argv'][] = '--debug';
7+
$_SERVER['argv'][] = '--configuration';
8+
$_SERVER['argv'][] = __DIR__ . '/_files/deprecation-trigger-class';
9+
10+
require __DIR__ . '/../../bootstrap.php';
11+
12+
(new PHPUnit\TextUI\Application)->run($_SERVER['argv']);
13+
--EXPECTF--
14+
PHPUnit Started (PHPUnit %s using %s)
15+
Test Runner Configured
16+
Bootstrap Finished (%sautoload.php)
17+
Event Facade Sealed
18+
Test Suite Loaded (1 test)
19+
Test Runner Started
20+
Test Suite Sorted
21+
Test Runner Execution Started (1 test)
22+
Test Suite Started (%sphpunit.xml, 1 test)
23+
Test Suite Started (default, 1 test)
24+
Test Suite Started (PHPUnit\TestFixture\SelfDirectIndirect\FirstPartyClassTest, 1 test)
25+
Test Preparation Started (PHPUnit\TestFixture\SelfDirectIndirect\FirstPartyClassTest::testOne)
26+
Test Prepared (PHPUnit\TestFixture\SelfDirectIndirect\FirstPartyClassTest::testOne)
27+
Test Triggered Deprecation (PHPUnit\TestFixture\SelfDirectIndirect\FirstPartyClassTest::testOne, issue triggered by third-party code, suppressed using operator) in %s:%d
28+
This class is deprecated
29+
Test Passed (PHPUnit\TestFixture\SelfDirectIndirect\FirstPartyClassTest::testOne)
30+
Test Finished (PHPUnit\TestFixture\SelfDirectIndirect\FirstPartyClassTest::testOne)
31+
Test Suite Finished (PHPUnit\TestFixture\SelfDirectIndirect\FirstPartyClassTest, 1 test)
32+
Test Suite Finished (default, 1 test)
33+
Test Suite Finished (%sphpunit.xml, 1 test)
34+
Test Runner Execution Finished
35+
Test Runner Finished
36+
PHPUnit Finished (Shell Exit Code: 0)
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
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\Runner;
11+
12+
use const E_USER_DEPRECATED;
13+
use function trigger_error;
14+
use PHPUnit\Framework\Attributes\CoversClass;
15+
use PHPUnit\Framework\Attributes\Small;
16+
use PHPUnit\Framework\TestCase;
17+
use ReflectionClass;
18+
19+
#[CoversClass(ErrorHandler::class)]
20+
#[Small]
21+
final class ErrorHandlerTest extends TestCase
22+
{
23+
public function testThrowsExceptionWhenUsingInvalidOrderOption(): void
24+
{
25+
$errorHandler = ErrorHandler::instance();
26+
$errorHandler->registerDeprecationHandler();
27+
trigger_error('deprecation', E_USER_DEPRECATED);
28+
$errorHandler->restoreDeprecationHandler();
29+
$refl = new ReflectionClass($errorHandler);
30+
$globalDeprecations = $refl->getProperty('globalDeprecations');
31+
$registeredDeprecations = $globalDeprecations->getValue($errorHandler);
32+
$this->assertCount(1, $registeredDeprecations);
33+
$this->assertSame('deprecation', $registeredDeprecations[0][1]);
34+
}
35+
}

0 commit comments

Comments
 (0)