Skip to content

Commit 46e0553

Browse files
committed
Implement TestCase->expectProcessExit($exitCode)
1 parent a62124f commit 46e0553

File tree

8 files changed

+111
-35
lines changed

8 files changed

+111
-35
lines changed

ProcessExitTest.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use PHPUnit\Framework\Attributes\CoversClass;
6+
use PHPUnit\Framework\Attributes\DataProvider;
7+
use PHPUnit\Framework\Attributes\RunInSeparateProcess;
8+
use PHPUnit\Framework\TestCase;
9+
10+
final class ProcessExitTest extends TestCase
11+
{
12+
#[RunInSeparateProcess]
13+
#[DataProvider("provideExitCodes")]
14+
public function testOne(?int $expectedExit, int $actualExitCode): void
15+
{
16+
if ($expectedExit !== null) {
17+
$this->expectProcessExit($expectedExit);
18+
}
19+
20+
exit($actualExitCode);
21+
}
22+
23+
static public function provideExitCodes():iterable {
24+
yield [null, 0];
25+
yield [null, 1];
26+
27+
yield [0, 0];
28+
yield [0, 1];
29+
30+
yield [1, 1];
31+
yield [1, 0];
32+
}
33+
}

src/Framework/TestCase.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,7 @@ abstract class TestCase extends Assert implements Reorderable, SelfDescribing, T
194194
private bool $outputRetrievedForAssertion = false;
195195
private bool $doesNotPerformAssertions = false;
196196
private bool $expectErrorLog = false;
197+
private ?int $expectProcessExit = null;
197198

198199
/**
199200
* @var list<Comparator>
@@ -1035,6 +1036,16 @@ final protected function expectOutputString(string $expectedString): void
10351036
$this->outputExpectedString = $expectedString;
10361037
}
10371038

1039+
final protected function expectProcessExit(int $exitCode): void
1040+
{
1041+
$this->expectProcessExit = $exitCode;
1042+
}
1043+
1044+
final public function getExpectedProcessExitCode(): ?int
1045+
{
1046+
return $this->expectProcessExit;
1047+
}
1048+
10381049
final protected function expectErrorLog(): void
10391050
{
10401051
$this->expectErrorLog = true;

src/Framework/TestRunner/ChildProcessResultProcessor.php

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ public function __construct(Facade $eventFacade, Emitter $emitter, PassedTests $
3737
$this->codeCoverage = $codeCoverage;
3838
}
3939

40-
public function process(Test $test, string $serializedProcessResult, string $stderr): void
40+
public function process(Test $test, string $serializedProcessResult, string $stderr, int $exitCode): void
4141
{
4242
if ($stderr !== '') {
4343
$exception = new Exception(trim($stderr));
@@ -74,6 +74,16 @@ public function process(Test $test, string $serializedProcessResult, string $std
7474
return;
7575
}
7676

77+
if ($childResult->expectedProcessExit !== null && $childResult->testCalledExit === true) {
78+
assert($test instanceof TestCase);
79+
80+
$test->assertSame($childResult->expectedProcessExit, $exitCode, 'Process exit-code expectation failed');
81+
} elseif ($childResult->expectedProcessExit !== null && $childResult->testCalledExit === false) {
82+
$test->fail('Process expected exit() to be called but test did not call it');
83+
} elseif ($childResult->expectedProcessExit === null && $childResult->testCalledExit === false) {
84+
$test->fail('Process called exit() but the test did not expect it');
85+
}
86+
7787
$this->eventFacade->forward($childResult->events);
7888
$this->passedTests->import($childResult->passedTests);
7989

src/Framework/TestRunner/templates/class.tpl

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -75,11 +75,29 @@ function __phpunit_run_isolated_test()
7575
$test->setInIsolation(true);
7676

7777
ob_end_clean();
78+
$output = '';
79+
$testCalledExit = true;
80+
register_shutdown_function(function() use ($test, $output, $dispatcher, $testCalledExit) {
81+
file_put_contents(
82+
'{processResultFile}',
83+
serialize(
84+
(object)[
85+
'testResult' => $test->result(),
86+
'codeCoverage' => {collectCodeCoverageInformation} ? CodeCoverage::instance()->codeCoverage() : null,
87+
'numAssertions' => $test->numberOfAssertionsPerformed(),
88+
'testCalledExit' => $testCalledExit,
89+
'expectedProcessExit' => $test->getExpectedProcessExitCode(),
90+
'output' => $output,
91+
'events' => $dispatcher->flush(),
92+
'passedTests' => PassedTests::instance(),
93+
]
94+
)
95+
);
96+
});
7897

7998
$test->run();
8099

81-
$output = '';
82-
100+
$testCalledExit = false;
83101
if (!$test->expectsOutput()) {
84102
$output = $test->output();
85103
}
@@ -98,20 +116,6 @@ function __phpunit_run_isolated_test()
98116
@rewind(STDOUT);
99117
}
100118
}
101-
102-
file_put_contents(
103-
'{processResultFile}',
104-
serialize(
105-
(object)[
106-
'testResult' => $test->result(),
107-
'codeCoverage' => {collectCodeCoverageInformation} ? CodeCoverage::instance()->codeCoverage() : null,
108-
'numAssertions' => $test->numberOfAssertionsPerformed(),
109-
'output' => $output,
110-
'events' => $dispatcher->flush(),
111-
'passedTests' => PassedTests::instance()
112-
]
113-
)
114-
);
115119
}
116120

117121
function __phpunit_error_handler($errno, $errstr, $errfile, $errline)

src/Framework/TestRunner/templates/method.tpl

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -75,11 +75,29 @@ function __phpunit_run_isolated_test()
7575
$test->setInIsolation(true);
7676

7777
ob_end_clean();
78+
$output = '';
79+
$testCalledExit = true;
80+
register_shutdown_function(function() use ($test, $output, $dispatcher, $testCalledExit) {
81+
file_put_contents(
82+
'{processResultFile}',
83+
serialize(
84+
(object)[
85+
'testResult' => $test->result(),
86+
'codeCoverage' => {collectCodeCoverageInformation} ? CodeCoverage::instance()->codeCoverage() : null,
87+
'numAssertions' => $test->numberOfAssertionsPerformed(),
88+
'testCalledExit' => $testCalledExit,
89+
'expectedProcessExit' => $test->getExpectedProcessExitCode(),
90+
'output' => $output,
91+
'events' => $dispatcher->flush(),
92+
'passedTests' => PassedTests::instance(),
93+
]
94+
)
95+
);
96+
});
7897

7998
$test->run();
8099

81-
$output = '';
82-
100+
$testCalledExit = false;
83101
if (!$test->expectsOutput()) {
84102
$output = $test->output();
85103
}
@@ -98,20 +116,6 @@ function __phpunit_run_isolated_test()
98116
@rewind(STDOUT);
99117
}
100118
}
101-
102-
file_put_contents(
103-
'{processResultFile}',
104-
serialize(
105-
(object)[
106-
'testResult' => $test->result(),
107-
'codeCoverage' => {collectCodeCoverageInformation} ? CodeCoverage::instance()->codeCoverage() : null,
108-
'numAssertions' => $test->numberOfAssertionsPerformed(),
109-
'output' => $output,
110-
'events' => $dispatcher->flush(),
111-
'passedTests' => PassedTests::instance()
112-
]
113-
)
114-
);
115119
}
116120

117121
function __phpunit_error_handler($errno, $errstr, $errfile, $errline)

src/Util/PHP/DefaultJobRunner.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,12 @@ private function runProcess(Job $job, ?string $temporaryFile): Result
147147
fclose($pipes[2]);
148148
}
149149

150+
$exitCode = 0;
151+
$processStatus = proc_get_status($process);
152+
if ($processStatus['running'] === false) {
153+
$exitCode = $processStatus['exitcode'];
154+
}
155+
150156
proc_close($process);
151157

152158
if ($temporaryFile !== null) {
@@ -156,7 +162,7 @@ private function runProcess(Job $job, ?string $temporaryFile): Result
156162
assert($stdout !== false);
157163
assert($stderr !== false);
158164

159-
return new Result($stdout, $stderr);
165+
return new Result($stdout, $stderr, $exitCode);
160166
}
161167

162168
/**

src/Util/PHP/JobRunner.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ final public function runTestJob(Job $job, string $processResultFile, Test $test
5252
$test,
5353
$processResult,
5454
$result->stderr(),
55+
$result->exitCode(),
5556
);
5657

5758
EventFacade::emitter()->childProcessFinished($result->stdout(), $result->stderr());

src/Util/PHP/Result.php

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,13 @@
2020
{
2121
private string $stdout;
2222
private string $stderr;
23+
private int $exitCode;
2324

24-
public function __construct(string $stdout, string $stderr)
25+
public function __construct(string $stdout, string $stderr, int $exitCode)
2526
{
2627
$this->stdout = $stdout;
2728
$this->stderr = $stderr;
29+
$this->exitCode = $exitCode;
2830
}
2931

3032
public function stdout(): string
@@ -36,4 +38,9 @@ public function stderr(): string
3638
{
3739
return $this->stderr;
3840
}
41+
42+
public function exitCode(): int
43+
{
44+
return $this->exitCode;
45+
}
3946
}

0 commit comments

Comments
 (0)