Skip to content
This repository was archived by the owner on Nov 5, 2025. It is now read-only.

Commit 03800bd

Browse files
Refactor
1 parent db0848e commit 03800bd

File tree

4 files changed

+128
-54
lines changed

4 files changed

+128
-54
lines changed

tests/src/EventTestCase.php

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,17 @@ abstract class EventTestCase extends TestCase
3232
private CollectingEventDispatcher $dispatcher;
3333

3434
/**
35-
* @var list<non-empty-string>
35+
* @var list<array{className: class-string, description: non-empty-string}>
3636
*/
3737
private array $given = [];
38-
private string $when;
3938

4039
/**
41-
* @var list<non-empty-string>
40+
* @var array{className: class-string, description: non-empty-string}
41+
*/
42+
private array $when;
43+
44+
/**
45+
* @var list<array{className: class-string, description: non-empty-string}>
4246
*/
4347
private array $then = [];
4448

@@ -64,7 +68,10 @@ final protected function given(Event ...$events): void
6468
->willReturn($events);
6569

6670
foreach ($events as $event) {
67-
$this->given[] = $event->asString();
71+
$this->given[] = [
72+
'className' => $event::class,
73+
'description' => $event->asString(),
74+
];
6875
}
6976
}
7077

@@ -74,7 +81,10 @@ final protected function when(PurchaseGoodCommand|SellGoodCommand $command): voi
7481

7582
$processor->process($command);
7683

77-
$this->when = $command->asString();
84+
$this->when = [
85+
'className' => $command::class,
86+
'description' => $command->asString(),
87+
];
7888
}
7989

8090
final protected function then(Event ...$events): void
@@ -94,7 +104,10 @@ final protected function then(Event ...$events): void
94104
}
95105

96106
foreach ($events as $event) {
97-
$this->then[] = $event->asString();
107+
$this->then[] = [
108+
'className' => $event::class,
109+
'description' => $event->asString(),
110+
];
98111
}
99112

100113
$this->provideAdditionalInformation(

tests/src/extension/AdditionalInformationProvidedSubscriber.php

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@
66

77
/**
88
* @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
9-
*
10-
* @internal This class is not covered by the backward compatibility promise for PHPUnit
119
*/
1210
final readonly class AdditionalInformationProvidedSubscriber extends Subscriber implements TestProvidedAdditionalInformationSubscriber
1311
{

tests/src/extension/Extension.php

Lines changed: 93 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,24 @@
33

44
use const DIRECTORY_SEPARATOR;
55
use const JSON_THROW_ON_ERROR;
6-
use function array_is_list;
6+
use function array_column;
7+
use function array_merge;
78
use function array_pop;
9+
use function array_unique;
10+
use function array_values;
811
use function assert;
912
use function exec;
1013
use function explode;
1114
use function file_put_contents;
1215
use function in_array;
13-
use function is_array;
1416
use function is_dir;
15-
use function is_string;
1617
use function json_decode;
1718
use function mkdir;
1819
use function sprintf;
1920
use function sys_get_temp_dir;
2021
use function tempnam;
2122
use function unlink;
23+
use PHPUnit\Event\Code\TestMethod;
2224
use PHPUnit\Event\Test\AdditionalInformationProvided;
2325
use PHPUnit\Runner\Extension\Extension as ExtensionInterface;
2426
use PHPUnit\Runner\Extension\Facade as ExtensionFacade;
@@ -37,6 +39,16 @@ final class Extension implements ExtensionInterface
3739
*/
3840
private string $format;
3941

42+
/**
43+
* @var array<class-string, array{uses: list<class-string>, emits: list<class-string>}>
44+
*/
45+
private array $commands;
46+
47+
/**
48+
* @var list<array{test: TestMethod, given: list<non-empty-string>, when: non-empty-string, then: list<non-empty-string>}>
49+
*/
50+
private array $tests;
51+
4052
public function bootstrap(Configuration $configuration, ExtensionFacade $facade, ParameterCollection $parameters): void
4153
{
4254
$targetDirectory = '/tmp';
@@ -61,64 +73,99 @@ public function bootstrap(Configuration $configuration, ExtensionFacade $facade,
6173

6274
$this->format = $format;
6375

64-
$facade->registerSubscriber(new AdditionalInformationProvidedSubscriber($this));
76+
$facade->registerSubscribers(
77+
new AdditionalInformationProvidedSubscriber($this),
78+
new TestRunnerFinishedSubscriber($this),
79+
);
6580
}
6681

6782
public function testProvidedAdditionalInformation(AdditionalInformationProvided $event): void
6883
{
84+
/**
85+
* @var array{given: list<array{className: class-string, description: non-empty-string}>, when: array{className: class-string, description: non-empty-string}, then: list<array{className: class-string, description: non-empty-string}>} $data
86+
*/
6987
$data = json_decode($event->additionalInformation(), true, flags: JSON_THROW_ON_ERROR);
7088

71-
assert(is_array($data));
72-
assert(isset($data['given']));
73-
assert(is_array($data['given']));
74-
assert(array_is_list($data['given']));
75-
assert(isset($data['when']));
76-
assert(is_string($data['when']));
77-
assert(isset($data['then']));
78-
assert(is_array($data['then']));
79-
assert(array_is_list($data['then']));
80-
81-
$tmp = explode('\\', $event->test()->className());
82-
$className = array_pop($tmp);
83-
84-
$dot = (new DotRenderer)->render(
85-
/** @phpstan-ignore argument.type */
86-
$data['given'],
87-
/** @phpstan-ignore argument.type */
88-
$data['when'],
89-
/** @phpstan-ignore argument.type */
90-
$data['then'],
89+
if (!isset($this->commands[$data['when']['className']])) {
90+
$this->commands[$data['when']['className']] = [
91+
'uses' => [],
92+
'emits' => [],
93+
];
94+
}
95+
96+
$this->commands[$data['when']['className']]['uses'] = array_values(
97+
array_unique(
98+
array_merge(
99+
$this->commands[$data['when']['className']]['uses'],
100+
array_column($data['given'], 'className'),
101+
),
102+
),
91103
);
92104

93-
$target = sprintf(
94-
'%s%s%s_%s.%s',
95-
$this->targetDirectory,
96-
DIRECTORY_SEPARATOR,
97-
$className,
98-
$event->test()->methodName(),
99-
$this->format,
105+
$this->commands[$data['when']['className']]['emits'] = array_values(
106+
array_unique(
107+
array_merge(
108+
$this->commands[$data['when']['className']]['emits'],
109+
array_column($data['then'], 'className'),
110+
),
111+
),
100112
);
101113

102-
if ($this->format === 'dot') {
103-
file_put_contents($target, $dot);
114+
$this->tests[] = [
115+
'test' => $event->test(),
116+
'given' => array_column($data['given'], 'description'),
117+
'when' => $data['when']['description'],
118+
'then' => array_column($data['then'], 'description'),
119+
];
120+
}
104121

105-
return;
106-
}
122+
public function testRunnerFinished(): void
123+
{
124+
$this->renderTests();
125+
}
107126

108-
$tmpFile = tempnam(sys_get_temp_dir(), 'graphviz');
127+
private function renderTests(): void
128+
{
129+
foreach ($this->tests as $test) {
130+
$tmp = explode('\\', $test['test']->className());
131+
$className = array_pop($tmp);
132+
133+
$dot = (new DotRenderer)->render(
134+
$test['given'],
135+
$test['when'],
136+
$test['then'],
137+
);
138+
139+
$target = sprintf(
140+
'%s%s%s_%s.%s',
141+
$this->targetDirectory,
142+
DIRECTORY_SEPARATOR,
143+
$className,
144+
$test['test']->methodName(),
145+
$this->format,
146+
);
109147

110-
file_put_contents($tmpFile, $dot);
148+
if ($this->format === 'dot') {
149+
file_put_contents($target, $dot);
111150

112-
exec(
113-
sprintf(
114-
'dot -T%s -o %s %s > /dev/null 2>&1',
115-
$this->format,
116-
$target,
117-
$tmpFile,
118-
),
119-
);
151+
return;
152+
}
153+
154+
$tmpFile = tempnam(sys_get_temp_dir(), 'graphviz');
120155

121-
unlink($tmpFile);
156+
file_put_contents($tmpFile, $dot);
157+
158+
exec(
159+
sprintf(
160+
'dot -T%s -o %s %s > /dev/null 2>&1',
161+
$this->format,
162+
$target,
163+
$tmpFile,
164+
),
165+
);
166+
167+
unlink($tmpFile);
168+
}
122169
}
123170

124171
/**
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php declare(strict_types=1);
2+
namespace example\framework\event\test\extension;
3+
4+
use PHPUnit\Event\TestRunner\Finished as TestRunnerFinished;
5+
use PHPUnit\Event\TestRunner\FinishedSubscriber as PhpunitTestRunnerFinishedSubscriber;
6+
7+
/**
8+
* @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
9+
*/
10+
final readonly class TestRunnerFinishedSubscriber extends Subscriber implements PhpunitTestRunnerFinishedSubscriber
11+
{
12+
public function notify(TestRunnerFinished $event): void
13+
{
14+
$this->extension()->testRunnerFinished();
15+
}
16+
}

0 commit comments

Comments
 (0)