Skip to content

Commit cf880b2

Browse files
Merge branch '11.5' into 12.3
2 parents f21a755 + 30bed97 commit cf880b2

File tree

10 files changed

+254
-16
lines changed

10 files changed

+254
-16
lines changed

ChangeLog-12.3.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ All notable changes of the PHPUnit 12.3 release series are documented in this fi
1212
### Fixed
1313

1414
* [#5863](https://github.com/sebastianbergmann/phpunit/issues/5863): TestDox printer does not show previous exception
15+
* [#6102](https://github.com/sebastianbergmann/phpunit/issues/6102): `expectUserDeprecationMessage*()` fails when test is run in separate process
1516

1617
## [12.3.4] - 2025-08-12
1718

src/Event/Dispatcher/CollectingDispatcher.php

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99
*/
1010
namespace PHPUnit\Event;
1111

12+
use PHPUnit\Runner\DeprecationCollector\Facade as DeprecationCollector;
13+
use PHPUnit\Runner\DeprecationCollector\TestTriggeredDeprecationSubscriber;
14+
1215
/**
1316
* @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
1417
*
@@ -17,15 +20,25 @@
1720
final class CollectingDispatcher implements Dispatcher
1821
{
1922
private EventCollection $events;
23+
private DirectDispatcher $isolatedDirectDispatcher;
2024

21-
public function __construct()
25+
public function __construct(DirectDispatcher $directDispatcher)
2226
{
23-
$this->events = new EventCollection;
27+
$this->isolatedDirectDispatcher = $directDispatcher;
28+
$this->events = new EventCollection;
29+
30+
$this->isolatedDirectDispatcher->registerSubscriber(new TestTriggeredDeprecationSubscriber(DeprecationCollector::collector()));
2431
}
2532

2633
public function dispatch(Event $event): void
2734
{
2835
$this->events->add($event);
36+
37+
try {
38+
$this->isolatedDirectDispatcher->dispatch($event);
39+
} catch (UnknownEventTypeException) {
40+
// Do nothing.
41+
}
2942
}
3043

3144
public function flush(): EventCollection

src/Event/Facade.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
use function interface_exists;
1414
use PHPUnit\Event\Telemetry\HRTime;
1515
use PHPUnit\Event\Telemetry\SystemGarbageCollectorStatusProvider;
16+
use PHPUnit\Runner\DeprecationCollector\Facade as DeprecationCollector;
1617

1718
/**
1819
* @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
@@ -89,7 +90,11 @@ public function registerTracer(Tracer\Tracer $tracer): void
8990
*/
9091
public function initForIsolation(HRTime $offset): CollectingDispatcher
9192
{
92-
$dispatcher = new CollectingDispatcher;
93+
DeprecationCollector::initForIsolation();
94+
95+
$dispatcher = new CollectingDispatcher(
96+
new DirectDispatcher($this->typeMap()),
97+
);
9398

9499
$this->emitter = new DispatchingEmitter(
95100
$dispatcher,

src/Runner/DeprecationCollector/Facade.php

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@
99
*/
1010
namespace PHPUnit\Runner\DeprecationCollector;
1111

12+
use PHPUnit\Event\EventFacadeIsSealedException;
1213
use PHPUnit\Event\Facade as EventFacade;
14+
use PHPUnit\Event\UnknownSubscriberTypeException;
1315
use PHPUnit\TestRunner\IssueFilter;
1416
use PHPUnit\TextUI\Configuration\Registry as ConfigurationRegistry;
1517

@@ -20,13 +22,21 @@
2022
*/
2123
final class Facade
2224
{
23-
private static ?Collector $collector = null;
25+
private static null|Collector|InIsolationCollector $collector = null;
26+
private static bool $inIsolation = false;
2427

2528
public static function init(): void
2629
{
2730
self::collector();
2831
}
2932

33+
public static function initForIsolation(): void
34+
{
35+
self::collector();
36+
37+
self::$inIsolation = true;
38+
}
39+
3040
/**
3141
* @return list<non-empty-string>
3242
*/
@@ -43,17 +53,33 @@ public static function filteredDeprecations(): array
4353
return self::collector()->filteredDeprecations();
4454
}
4555

46-
private static function collector(): Collector
56+
/**
57+
* @throws EventFacadeIsSealedException
58+
* @throws UnknownSubscriberTypeException
59+
*/
60+
public static function collector(): Collector|InIsolationCollector
4761
{
48-
if (self::$collector === null) {
49-
self::$collector = new Collector(
50-
EventFacade::instance(),
51-
new IssueFilter(
52-
ConfigurationRegistry::get()->source(),
53-
),
62+
if (self::$collector !== null) {
63+
return self::$collector;
64+
}
65+
66+
$issueFilter = new IssueFilter(
67+
ConfigurationRegistry::get()->source(),
68+
);
69+
70+
if (self::$inIsolation) {
71+
self::$collector = new InIsolationCollector(
72+
$issueFilter,
5473
);
74+
75+
return self::$collector;
5576
}
5677

78+
self::$collector = new Collector(
79+
EventFacade::instance(),
80+
$issueFilter,
81+
);
82+
5783
return self::$collector;
5884
}
5985
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
<?php declare(strict_types=1);
2+
/*
3+
* This file is part of PHPUnit.
4+
*
5+
* (c) Sebastian Bergmann <[email protected]>
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\DeprecationCollector;
11+
12+
use PHPUnit\Event\Test\DeprecationTriggered;
13+
use PHPUnit\TestRunner\IssueFilter;
14+
15+
/**
16+
* @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
17+
*
18+
* @internal This class is not covered by the backward compatibility promise for PHPUnit
19+
*/
20+
final class InIsolationCollector
21+
{
22+
private readonly IssueFilter $issueFilter;
23+
24+
/**
25+
* @var list<non-empty-string>
26+
*/
27+
private array $deprecations = [];
28+
29+
/**
30+
* @var list<non-empty-string>
31+
*/
32+
private array $filteredDeprecations = [];
33+
34+
public function __construct(IssueFilter $issueFilter)
35+
{
36+
$this->issueFilter = $issueFilter;
37+
}
38+
39+
/**
40+
* @return list<non-empty-string>
41+
*/
42+
public function deprecations(): array
43+
{
44+
return $this->deprecations;
45+
}
46+
47+
/**
48+
* @return list<non-empty-string>
49+
*/
50+
public function filteredDeprecations(): array
51+
{
52+
return $this->filteredDeprecations;
53+
}
54+
55+
public function testTriggeredDeprecation(DeprecationTriggered $event): void
56+
{
57+
$this->deprecations[] = $event->message();
58+
59+
if (!$this->issueFilter->shouldBeProcessed($event)) {
60+
return;
61+
}
62+
63+
$this->filteredDeprecations[] = $event->message();
64+
}
65+
}

src/Runner/DeprecationCollector/Subscriber/Subscriber.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,14 @@
1616
*/
1717
abstract class Subscriber
1818
{
19-
private readonly Collector $collector;
19+
private readonly Collector|InIsolationCollector $collector;
2020

21-
public function __construct(Collector $collector)
21+
public function __construct(Collector|InIsolationCollector $collector)
2222
{
2323
$this->collector = $collector;
2424
}
2525

26-
protected function collector(): Collector
26+
protected function collector(): Collector|InIsolationCollector
2727
{
2828
return $this->collector;
2929
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
<?php declare(strict_types=1);
2+
/*
3+
* This file is part of PHPUnit.
4+
*
5+
* (c) Sebastian Bergmann <[email protected]>
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\Event;
11+
12+
use const E_USER_DEPRECATED;
13+
use function trigger_error;
14+
use PHPUnit\Framework\Attributes\IgnoreDeprecations;
15+
use PHPUnit\Framework\Attributes\RunTestsInSeparateProcesses;
16+
use PHPUnit\Framework\TestCase;
17+
18+
#[RunTestsInSeparateProcesses]
19+
final class TestForDeprecatedFeatureInIsolationTest extends TestCase
20+
{
21+
#[IgnoreDeprecations]
22+
public function testExpectationOnExactDeprecationMessageWorksWhenExpectedDeprecationIsTriggered(): void
23+
{
24+
$this->expectUserDeprecationMessage('message');
25+
26+
@trigger_error('message', E_USER_DEPRECATED);
27+
}
28+
29+
#[IgnoreDeprecations]
30+
public function testExpectationsOnExactDeprecationMessagesWorkWhenExpectedDeprecationsAreTriggered(): void
31+
{
32+
$this->expectUserDeprecationMessage('message');
33+
$this->expectUserDeprecationMessage('another message');
34+
35+
@trigger_error('message', E_USER_DEPRECATED);
36+
@trigger_error('another message', E_USER_DEPRECATED);
37+
}
38+
39+
#[IgnoreDeprecations]
40+
public function testExpectationOnExactDeprecationMessageWorksWhenExpectedDeprecationIsNotTriggered(): void
41+
{
42+
$this->expectUserDeprecationMessage('message');
43+
}
44+
45+
#[IgnoreDeprecations]
46+
public function testExpectationOnExactDeprecationMessageWorksWhenUnexpectedDeprecationIsTriggered(): void
47+
{
48+
$this->expectUserDeprecationMessage('message');
49+
50+
@trigger_error('another message', E_USER_DEPRECATED);
51+
}
52+
53+
#[IgnoreDeprecations]
54+
public function testExpectationOnDeprecationMessageMatchingRegularExpressionWorksWhenExpectedDeprecationIsTriggered(): void
55+
{
56+
$this->expectUserDeprecationMessageMatches('/message/');
57+
58+
@trigger_error('...message...', E_USER_DEPRECATED);
59+
}
60+
61+
#[IgnoreDeprecations]
62+
public function testExpectationsOnDeprecationMessagesMatchingRegularExpressionsWorkWhenExpectedDeprecationsAreTriggered(): void
63+
{
64+
$this->expectUserDeprecationMessageMatches('/foo/');
65+
$this->expectUserDeprecationMessageMatches('/bar/');
66+
67+
@trigger_error('...foo...', E_USER_DEPRECATED);
68+
@trigger_error('...bar...', E_USER_DEPRECATED);
69+
}
70+
71+
#[IgnoreDeprecations]
72+
public function testExpectationOnDeprecationMessageMatchingRegularExpressionWorksWhenExpectedDeprecationIsNotTriggered(): void
73+
{
74+
$this->expectUserDeprecationMessageMatches('/message/');
75+
}
76+
77+
#[IgnoreDeprecations]
78+
public function testExpectationOnDeprecationMessageMatchingRegularExpressionWorksWhenUnepectedDeprecationIsTriggered(): void
79+
{
80+
$this->expectUserDeprecationMessageMatches('/message/');
81+
82+
@trigger_error('something else', E_USER_DEPRECATED);
83+
}
84+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
--TEST--
2+
https://github.com/sebastianbergmann/phpunit/issues/6102
3+
--XFAIL--
4+
https://github.com/sebastianbergmann/phpunit/issues/6102
5+
--FILE--
6+
<?php declare(strict_types=1);
7+
$_SERVER['argv'][] = '--do-not-cache-result';
8+
$_SERVER['argv'][] = '--no-configuration';
9+
$_SERVER['argv'][] = __DIR__ . '/../../end-to-end/generic/_files/TestForDeprecatedFeatureInIsolationTest.php';
10+
11+
require __DIR__ . '/../../bootstrap.php';
12+
13+
(new PHPUnit\TextUI\Application)->run($_SERVER['argv']);
14+
--EXPECTF--
15+
PHPUnit %s by Sebastian Bergmann and contributors.
16+
17+
Runtime: %s
18+
19+
..FF..FF 8 / 8 (100%)
20+
21+
Time: %s, Memory: %s
22+
23+
There were 4 failures:
24+
25+
1) PHPUnit\TestFixture\Event\TestForDeprecatedFeatureInIsolationTest::testExpectationOnExactDeprecationMessageWorksWhenExpectedDeprecationIsNotTriggered
26+
Expected deprecation with message "message" was not triggered
27+
28+
2) PHPUnit\TestFixture\Event\TestForDeprecatedFeatureInIsolationTest::testExpectationOnExactDeprecationMessageWorksWhenUnexpectedDeprecationIsTriggered
29+
Expected deprecation with message "message" was not triggered
30+
31+
3) PHPUnit\TestFixture\Event\TestForDeprecatedFeatureInIsolationTest::testExpectationOnDeprecationMessageMatchingRegularExpressionWorksWhenExpectedDeprecationIsNotTriggered
32+
Expected deprecation with message matching regular expression "/message/" was not triggered
33+
34+
4) PHPUnit\TestFixture\Event\TestForDeprecatedFeatureInIsolationTest::testExpectationOnDeprecationMessageMatchingRegularExpressionWorksWhenUnepectedDeprecationIsTriggered
35+
Expected deprecation with message matching regular expression "/message/" was not triggered
36+
37+
FAILURES!
38+
Tests: 8, Assertions: 10, Failures: 4.

tests/unit/Event/Dispatcher/CollectingDispatcherTest.php

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,20 @@ final class CollectingDispatcherTest extends TestCase
1919
{
2020
public function testHasNoCollectedEventsWhenFlushedImmediatelyAfterCreation(): void
2121
{
22-
$dispatcher = new CollectingDispatcher;
22+
$typeMap = new TypeMap;
23+
$typeMap->addMapping(Test\DeprecationTriggeredSubscriber::class, Test\DeprecationTriggered::class);
24+
25+
$dispatcher = new CollectingDispatcher(new DirectDispatcher($typeMap));
2326

2427
$this->assertEmpty($dispatcher->flush());
2528
}
2629

2730
public function testCollectsDispatchedEventsUntilFlushed(): void
2831
{
29-
$dispatcher = new CollectingDispatcher;
32+
$typeMap = new TypeMap;
33+
$typeMap->addMapping(Test\DeprecationTriggeredSubscriber::class, Test\DeprecationTriggered::class);
34+
35+
$dispatcher = new CollectingDispatcher(new DirectDispatcher($typeMap));
3036
$event = $this->createStub(Event::class);
3137

3238
$dispatcher->dispatch($event);

0 commit comments

Comments
 (0)