Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Output buffer - fix 5851 #5852

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
228 changes: 213 additions & 15 deletions src/Framework/TestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,13 @@
use function is_string;
use function libxml_clear_errors;
use function method_exists;
use function ob_clean;
use function ob_end_clean;
use function ob_get_clean;
use function ob_end_flush;
use function ob_flush;
use function ob_get_contents;
use function ob_get_level;
use function ob_get_status;
use function ob_start;
use function parse_url;
use function pathinfo;
Expand Down Expand Up @@ -191,6 +194,7 @@
private ?string $outputExpectedString = null;
private bool $outputBufferingActive = false;
private int $outputBufferingLevel;
private ?int $outputBufferingFlushed = null;
private bool $outputRetrievedForAssertion = false;
private bool $doesNotPerformAssertions = false;

Expand Down Expand Up @@ -452,7 +456,7 @@
*
* @internal This method is not covered by the backward compatibility promise for PHPUnit
*/
final public function runBare(): void

Check warning on line 459 in src/Framework/TestCase.php

View workflow job for this annotation

GitHub Actions / Mutation Testing

Escaped Mutant for Mutator "PublicVisibility": --- Original +++ New @@ @@ * * @internal This method is not covered by the backward compatibility promise for PHPUnit */ - final public function runBare(): void + final protected function runBare(): void { $emitter = Event\Facade::emitter(); error_clear_last();
{
$emitter = Event\Facade::emitter();

Expand Down Expand Up @@ -557,12 +561,14 @@

$outputBufferingStopped = false;

if (!isset($e) &&

Check warning on line 564 in src/Framework/TestCase.php

View workflow job for this annotation

GitHub Actions / Mutation Testing

Escaped Mutant for Mutator "LogicalAnd": --- Original +++ New @@ @@ } } $outputBufferingStopped = false; - if (!isset($e) && $this->hasExpectationOnOutput()) { + if (!isset($e) || $this->hasExpectationOnOutput()) { // if it fails now, we shouldn't try again later either $outputBufferingStopped = true; if ($this->stopOutputBuffering()) {

Check warning on line 564 in src/Framework/TestCase.php

View workflow job for this annotation

GitHub Actions / Mutation Testing

Escaped Mutant for Mutator "LogicalAndAllSubExprNegation": --- Original +++ New @@ @@ } } $outputBufferingStopped = false; - if (!isset($e) && $this->hasExpectationOnOutput()) { + if (isset($e) && !$this->hasExpectationOnOutput()) { // if it fails now, we shouldn't try again later either $outputBufferingStopped = true; if ($this->stopOutputBuffering()) {

Check warning on line 564 in src/Framework/TestCase.php

View workflow job for this annotation

GitHub Actions / Mutation Testing

Escaped Mutant for Mutator "LogicalAndNegation": --- Original +++ New @@ @@ } } $outputBufferingStopped = false; - if (!isset($e) && $this->hasExpectationOnOutput()) { + if (!(!isset($e) && $this->hasExpectationOnOutput())) { // if it fails now, we shouldn't try again later either $outputBufferingStopped = true; if ($this->stopOutputBuffering()) {

Check warning on line 564 in src/Framework/TestCase.php

View workflow job for this annotation

GitHub Actions / Mutation Testing

Escaped Mutant for Mutator "LogicalAndSingleSubExprNegation": --- Original +++ New @@ @@ } } $outputBufferingStopped = false; - if (!isset($e) && $this->hasExpectationOnOutput()) { + if (!isset($e) && !$this->hasExpectationOnOutput()) { // if it fails now, we shouldn't try again later either $outputBufferingStopped = true; if ($this->stopOutputBuffering()) {
$this->hasExpectationOnOutput() &&
$this->stopOutputBuffering()) {
$this->hasExpectationOnOutput()) {
// if it fails now, we shouldn't try again later either
$outputBufferingStopped = true;

$this->performAssertionsOnOutput();
if ($this->stopOutputBuffering()) {
$this->performAssertionsOnOutput();
}
}

if ($this->status->isSuccess()) {
Expand Down Expand Up @@ -1813,43 +1819,235 @@
$this->status = TestStatus::skipped($message);
}

private function outputBufferingCallback(string $output, int $phase): string
{
// assign it here to not get output from uncleanable children at the end
// as well as to ensure we have all output available to check
// if any children buffers have a low chunk size and already returned data
// or ob_flush was called
if ($this->outputBufferingActive) {
$this->output .= $output;

Check warning on line 1829 in src/Framework/TestCase.php

View workflow job for this annotation

GitHub Actions / Mutation Testing

Escaped Mutant for Mutator "Assignment": --- Original +++ New @@ @@ // if any children buffers have a low chunk size and already returned data // or ob_flush was called if ($this->outputBufferingActive) { - $this->output .= $output; + $this->output = $output; if (($phase & PHP_OUTPUT_HANDLER_FINAL) === PHP_OUTPUT_HANDLER_FINAL) { // don't handle, since we report an error already if our handler is missing // since it's inconsistent here with ob_end_flush/ob_end_clean

if (($phase & PHP_OUTPUT_HANDLER_FINAL) === PHP_OUTPUT_HANDLER_FINAL) {

Check warning on line 1831 in src/Framework/TestCase.php

View workflow job for this annotation

GitHub Actions / Mutation Testing

Escaped Mutant for Mutator "BitwiseAnd": --- Original +++ New @@ @@ // or ob_flush was called if ($this->outputBufferingActive) { $this->output .= $output; - if (($phase & PHP_OUTPUT_HANDLER_FINAL) === PHP_OUTPUT_HANDLER_FINAL) { + if (($phase | PHP_OUTPUT_HANDLER_FINAL) === PHP_OUTPUT_HANDLER_FINAL) { // don't handle, since we report an error already if our handler is missing // since it's inconsistent here with ob_end_flush/ob_end_clean return '';

Check warning on line 1831 in src/Framework/TestCase.php

View workflow job for this annotation

GitHub Actions / Mutation Testing

Escaped Mutant for Mutator "Identical": --- Original +++ New @@ @@ // or ob_flush was called if ($this->outputBufferingActive) { $this->output .= $output; - if (($phase & PHP_OUTPUT_HANDLER_FINAL) === PHP_OUTPUT_HANDLER_FINAL) { + if (($phase & PHP_OUTPUT_HANDLER_FINAL) !== PHP_OUTPUT_HANDLER_FINAL) { // don't handle, since we report an error already if our handler is missing // since it's inconsistent here with ob_end_flush/ob_end_clean return '';
// don't handle, since we report an error already if our handler is missing
// since it's inconsistent here with ob_end_flush/ob_end_clean
return '';
}

if (($phase & PHP_OUTPUT_HANDLER_CLEAN) === PHP_OUTPUT_HANDLER_CLEAN) {
$this->outputBufferingFlushed = PHP_OUTPUT_HANDLER_CLEAN;
} elseif (($phase & PHP_OUTPUT_HANDLER_FLUSH) === PHP_OUTPUT_HANDLER_FLUSH) {
$this->outputBufferingFlushed = PHP_OUTPUT_HANDLER_FLUSH;
}
}

return '';
}

// private to ensure it cannot be restarted after ending it from outside this class
private function startOutputBuffering(): void
{
ob_start();
ob_start([$this, 'outputBufferingCallback']);

Check warning on line 1850 in src/Framework/TestCase.php

View workflow job for this annotation

GitHub Actions / Mutation Testing

Escaped Mutant for Mutator "ArrayItemRemoval": --- Original +++ New @@ @@ // private to ensure it cannot be restarted after ending it from outside this class private function startOutputBuffering(): void { - ob_start([$this, 'outputBufferingCallback']); + ob_start(['outputBufferingCallback']); $this->outputBufferingActive = true; $this->outputBufferingLevel = ob_get_level(); }

Check warning on line 1850 in src/Framework/TestCase.php

View workflow job for this annotation

GitHub Actions / Mutation Testing

Escaped Mutant for Mutator "FunctionCallRemoval": --- Original +++ New @@ @@ // private to ensure it cannot be restarted after ending it from outside this class private function startOutputBuffering(): void { - ob_start([$this, 'outputBufferingCallback']); + $this->outputBufferingActive = true; $this->outputBufferingLevel = ob_get_level(); }

$this->outputBufferingActive = true;
$this->outputBufferingLevel = ob_get_level();
}

/**
* @throws Exception
* @throws NoPreviousThrowableException
*/
private function stopOutputBuffering(): bool
{
$bufferingLevel = ob_get_level();
$bufferingLevel = ob_get_level();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At first, it is a bugfix, so it must target the lowest supported and problematic branch.

Also, it seems this PR fixes several ob issues. I would like to see a separate commit for each issue ("Fix ob is not cleanable", ...) so each can be reviewed individually.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At first, it is a bugfix, so it must target the lowest supported and problematic branch.

Could you give me a quick hint, since this is my first PR for phpunit - which branch would that be? Rebasing/Rebranching from that and implementing it on that branch is sufficient or is there anything else?

Also, it seems this PR fixes several ob issues. I would like to see a separate commit for each issue ("Fix ob is not cleanable", ...) so each can be reviewed individually.

Practically this isn't possible except for a single case (the error added for ob_flush/ob_clean), since all changes are needed for any of these cases to work correctly. Separating it would make it more confusing than it already is - due to the nature of output buffering.
In case you insist, could you please tell me the exact commits/how you want it separated, then I can see if it's possible or tell you exactly why it's not possible.

$bufferingStatus = ob_get_status();
$bufferingCallbackName = $bufferingStatus['name'] ?? '';
$expectedBufferingCallable = static::class . '::outputBufferingCallback';

if ($bufferingLevel !== $this->outputBufferingLevel ||
($this->outputBufferingActive && $bufferingCallbackName !== $expectedBufferingCallable) ||
$this->outputBufferingFlushed !== null) {
$asFailure = true;

if ($bufferingLevel !== $this->outputBufferingLevel) {
if ($bufferingLevel > $this->outputBufferingLevel) {
$message = 'Test code or tested code did not close its own output buffers';
} else {
} elseif ($bufferingLevel < $this->outputBufferingLevel) {
$message = 'Test code or tested code closed output buffers other than its own';
} elseif ($this->outputBufferingActive && $bufferingCallbackName !== $expectedBufferingCallable) {
$message = 'Test code or tested code first closed output buffers other than its own and later started output buffers it did not close';
} elseif ($this->outputBufferingFlushed !== null) {
// if we weren't in phpunit this would lead to a PHP notice
$message = 'Test code or tested code flushed or cleaned global output buffers other than its own';
} else {
$this->outputBufferingLevel = ob_get_level();

Check warning on line 1882 in src/Framework/TestCase.php

View check run for this annotation

Codecov / codecov/patch

src/Framework/TestCase.php#L1882

Added line #L1882 was not covered by tests

return true;

Check warning on line 1884 in src/Framework/TestCase.php

View check run for this annotation

Codecov / codecov/patch

src/Framework/TestCase.php#L1884

Added line #L1884 was not covered by tests
}

$hasExpectedCallable = false;

if ($this->outputBufferingActive) {
$fullObStatus = ob_get_status(true);
$bufferingCallbackNameLevel = $fullObStatus[$this->outputBufferingLevel - 1]['name'] ?? '';
$bufferingCallbackSizeUsed = $fullObStatus[$this->outputBufferingLevel - 1]['buffer_used'] ?? PHP_INT_MAX;

if ($bufferingCallbackNameLevel === $expectedBufferingCallable) {
$hasExpectedCallable = true;

foreach ($fullObStatus as $index => $obStatus) {
if ($index < $this->outputBufferingLevel) {
continue;
}

if (($obStatus['flags'] & PHP_OUTPUT_HANDLER_REMOVABLE) === PHP_OUTPUT_HANDLER_REMOVABLE) {
continue;
}

if (!$this->inIsolation && !$this->shouldRunInSeparateProcess()) {
$message = 'Test code contains a non-removable output buffer - run test in separate process to avoid side-effects';
$hasExpectedCallable = false;

break;
}

// allow non-removable handler 1 level deeper than our handler to allow unit tests for non-removable handlers
// however only if our own handler is empty, as we cannot retrieve that from our handler if we are in a non-removable handler in a level deeper
if ($index === $this->outputBufferingLevel && $bufferingCallbackSizeUsed === 0) {
continue;

Check warning on line 1916 in src/Framework/TestCase.php

View check run for this annotation

Codecov / codecov/patch

src/Framework/TestCase.php#L1915-L1916

Added lines #L1915 - L1916 were not covered by tests
}

if ($index === $this->outputBufferingLevel) {
$message = 'Tests with non-removable output buffer handlers must not call flush on them and the chunk size must be bigger than the expected output';

Check warning on line 1920 in src/Framework/TestCase.php

View check run for this annotation

Codecov / codecov/patch

src/Framework/TestCase.php#L1919-L1920

Added lines #L1919 - L1920 were not covered by tests
} else {
// we cannot get the data from the handlers between our handler and the topmost non-removable handler
$message = 'Tests with multiple output buffers where any, except the first, are non-removable are not supported';

Check warning on line 1923 in src/Framework/TestCase.php

View check run for this annotation

Codecov / codecov/patch

src/Framework/TestCase.php#L1923

Added line #L1923 was not covered by tests
}

$hasExpectedCallable = false;

Check warning on line 1926 in src/Framework/TestCase.php

View check run for this annotation

Codecov / codecov/patch

src/Framework/TestCase.php#L1926

Added line #L1926 was not covered by tests

break;

Check warning on line 1928 in src/Framework/TestCase.php

View check run for this annotation

Codecov / codecov/patch

src/Framework/TestCase.php#L1928

Added line #L1928 was not covered by tests
}

if ($hasExpectedCallable && $this->outputBufferingFlushed === null) {
$asFailure = false;
}
} else {
// the original buffer doesn't exist anymore at that level, which means it was closed
$message = 'Test code or tested code first closed output buffers other than its own and later started output buffers it did not close';
}
} else {
$asFailure = false;

Check warning on line 1939 in src/Framework/TestCase.php

View check run for this annotation

Codecov / codecov/patch

src/Framework/TestCase.php#L1939

Added line #L1939 was not covered by tests
}

while (ob_get_level() >= $this->outputBufferingLevel) {
ob_end_clean();
$obStatus = ob_get_status();

if ($obStatus === []) {
break;

Check warning on line 1946 in src/Framework/TestCase.php

View check run for this annotation

Codecov / codecov/patch

src/Framework/TestCase.php#L1946

Added line #L1946 was not covered by tests
}

// 'level' is off by 1 because 0-indexed
if ($hasExpectedCallable && $obStatus['name'] === $expectedBufferingCallable && $obStatus['level'] + 1 === $this->outputBufferingLevel) {
// our own handler
ob_end_clean();

continue;
}

if (($obStatus['flags'] & PHP_OUTPUT_HANDLER_REMOVABLE) === PHP_OUTPUT_HANDLER_REMOVABLE) {
// bubble it up
ob_end_flush();

continue;
}

if ($hasExpectedCallable && $obStatus['level'] === $this->outputBufferingLevel) {
$fullObStatus = ob_get_status(true);
$bufferingCallbackSizeUsed = $fullObStatus[$this->outputBufferingLevel - 1]['buffer_used'] ?? PHP_INT_MAX;

Check warning on line 1966 in src/Framework/TestCase.php

View check run for this annotation

Codecov / codecov/patch

src/Framework/TestCase.php#L1965-L1966

Added lines #L1965 - L1966 were not covered by tests

// we are 1 level deeper than our buffer
// check again to be sure, as we cannot retrieve what's in the buffer
if ($bufferingCallbackSizeUsed !== 0) {
$hasExpectedCallable = false;
$asFailure = true;
$message = 'Tests with non-removable output buffer handlers must not call flush on them and the chunk size must be bigger than the expected output';

Check warning on line 1973 in src/Framework/TestCase.php

View check run for this annotation

Codecov / codecov/patch

src/Framework/TestCase.php#L1970-L1973

Added lines #L1970 - L1973 were not covered by tests
} else {
// assign it since we cannot trigger our callback
// this is the reason why it's risky even then, since the ob callback of the non-removable buffer isn't called
// which could modify the output
$this->output .= (string) ob_get_contents();

Check warning on line 1978 in src/Framework/TestCase.php

View check run for this annotation

Codecov / codecov/patch

src/Framework/TestCase.php#L1978

Added line #L1978 was not covered by tests

// if we have the default output handler which doesn't modify output
// this isn't even risky
if ($obStatus['name'] === 'default output handler' && $this->outputBufferingFlushed === null) {
$message = null;
} elseif ($this->outputBufferingFlushed === null) {
$message = 'Non-removable output handler callback was not called, which could alter output';

Check warning on line 1985 in src/Framework/TestCase.php

View check run for this annotation

Codecov / codecov/patch

src/Framework/TestCase.php#L1982-L1985

Added lines #L1982 - L1985 were not covered by tests
} else {
$asFailure = true;

Check warning on line 1987 in src/Framework/TestCase.php

View check run for this annotation

Codecov / codecov/patch

src/Framework/TestCase.php#L1987

Added line #L1987 was not covered by tests
}
}
} elseif (($obStatus['flags'] & PHP_OUTPUT_HANDLER_FLUSHABLE) === PHP_OUTPUT_HANDLER_FLUSHABLE) {
// bubble it up
ob_flush();

Check warning on line 1992 in src/Framework/TestCase.php

View check run for this annotation

Codecov / codecov/patch

src/Framework/TestCase.php#L1992

Added line #L1992 was not covered by tests
}

if (($obStatus['flags'] & PHP_OUTPUT_HANDLER_CLEANABLE) === PHP_OUTPUT_HANDLER_CLEANABLE) {
// make sure it's empty for subsequent runs to reduce unrelated errors
ob_clean();

Check warning on line 1997 in src/Framework/TestCase.php

View check run for this annotation

Codecov / codecov/patch

src/Framework/TestCase.php#L1997

Added line #L1997 was not covered by tests
}

// can't end any parents either
break;
}

Event\Facade::emitter()->testConsideredRisky(
// reset it to stop adding more output
$this->outputBufferingActive = false;
$this->outputBufferingFlushed = null;
$this->outputBufferingLevel = ob_get_level();

if ($message === null) {
return true;

Check warning on line 2010 in src/Framework/TestCase.php

View check run for this annotation

Codecov / codecov/patch

src/Framework/TestCase.php#L2010

Added line #L2010 was not covered by tests
}

if (!$asFailure) {
Event\Facade::emitter()->testConsideredRisky(
$this->valueObjectForEvents(),
$message,
);

$this->status = TestStatus::risky($message);

return true;
}

// it's impossible to tell if there were any PHP errors or failed assertions
$this->status = TestStatus::failure($message);

Event\Facade::emitter()->testFailed(
$this->valueObjectForEvents(),
$message,
Event\Code\ThrowableBuilder::from(new Exception($message)),
null,
);

$this->status = TestStatus::risky($message);
if ($this->numberOfAssertionsPerformed() === 0 &&
$this->hasExpectationOnOutput()) {
// no error that no assertions were performed
$this->addToAssertionCount(1);
}

return false;
}

$this->output = ob_get_clean();
if (!$this->outputBufferingActive) {
return true;

Check warning on line 2043 in src/Framework/TestCase.php

View check run for this annotation

Codecov / codecov/patch

src/Framework/TestCase.php#L2043

Added line #L2043 was not covered by tests
}

$this->outputBufferingActive = false;
$this->outputBufferingLevel = ob_get_level();
ob_end_clean();

$this->outputBufferingActive = false;
$this->outputBufferingFlushed = null;
$this->outputBufferingLevel = ob_get_level();

return true;
}
Expand Down
14 changes: 4 additions & 10 deletions tests/end-to-end/regression/5342.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,15 @@ F 1 / 1 (100%)

Time: %s, Memory: %s

There was 1 failure:
There were 2 failures:

1) PHPUnit\TestFixture\Issue5342Test::testFailure
Failed asserting that false is true.

%sIssue5342Test.php:%i

--

There was 1 risky test:

1) PHPUnit\TestFixture\Issue5342Test::testFailure
Test code or tested code closed output buffers other than its own

%sIssue5342Test.php:%i
2) PHPUnit\TestFixture\Issue5342Test::testFailure
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this escalation from risky test to test failure intentional?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. I didn't plan that initially, but as I created the PR, I realized that more likely than not these ob issues lead to unexpected and non-trustworthy test results in many cases. Keeping them "risky" would not convey the severity of the issue here in my opinion.

I did keep "risky" in some cases (as you can see) though, were the behavior is usually not much different than if there were no ob issue at all.


Due to the nature of the buffer, the resulting logic/code is unfortunately a bit ugly, so feedback is very welcome.

PHPUnit\Framework\Exception: Test code or tested code first closed output buffers other than its own and later started output buffers it did not close

FAILURES!
Tests: 1, Assertions: 1, Failures: 1, Risky: 1.
Tests: 1, Assertions: 1, Failures: 2.
82 changes: 82 additions & 0 deletions tests/end-to-end/regression/5851.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
--TEST--
https://github.com/sebastianbergmann/phpunit/pull/5861
--FILE--
<?php declare(strict_types=1);
$_SERVER['argv'][] = '--do-not-cache-result';
$_SERVER['argv'][] = '--no-configuration';
$_SERVER['argv'][] = __DIR__ . '/5851/Issue5851Test.php';

require_once __DIR__ . '/../../bootstrap.php';
(new PHPUnit\TextUI\Application)->run($_SERVER['argv']);
--EXPECTF--
PHPUnit %s by Sebastian Bergmann and contributors.

Runtime: %s

FFFIllegaly hide thisFFSneakyFNaughtySafeFFRRFRF. 14 / 14 (100%)

Time: %s, Memory: %s

There were 10 failures:

1) PHPUnit\TestFixture\Issue5851Test::testInvalidFlushBuffer
PHPUnit\Framework\Exception: Test code or tested code flushed or cleaned global output buffers other than its own

2) PHPUnit\TestFixture\Issue5851Test::testInvalidSilencedFlushBuffer
PHPUnit\Framework\Exception: Test code or tested code flushed or cleaned global output buffers other than its own

3) PHPUnit\TestFixture\Issue5851Test::testInvalidFlushBufferEmpty
PHPUnit\Framework\Exception: Test code or tested code flushed or cleaned global output buffers other than its own

4) PHPUnit\TestFixture\Issue5851Test::testInvalidCleanExternalBuffer
PHPUnit\Framework\Exception: Test code or tested code flushed or cleaned global output buffers other than its own

5) PHPUnit\TestFixture\Issue5851Test::testRemovedAndAddedBufferNoOutput
PHPUnit\Framework\Exception: Test code or tested code first closed output buffers other than its own and later started output buffers it did not close

6) PHPUnit\TestFixture\Issue5851Test::testRemovedAndAddedBufferOutput
PHPUnit\Framework\Exception: Test code or tested code first closed output buffers other than its own and later started output buffers it did not close

7) PHPUnit\TestFixture\Issue5851Test::testRemovedAndAddedBufferExpectedOutput
PHPUnit\Framework\Exception: Test code or tested code first closed output buffers other than its own and later started output buffers it did not close

8) PHPUnit\TestFixture\Issue5851Test::testNonClosedBufferShouldntBeIgnored
Failed asserting that two strings are identical.
--- Expected
+++ Actual
@@ @@
-''
+'Do not ignore thisor this'

9) PHPUnit\TestFixture\Issue5851Test::testNonRemovableBuffer
PHPUnit\Framework\Exception: Test code contains a non-removable output buffer - run test in separate process to avoid side-effects

10) PHPUnit\TestFixture\Issue5851Test::testNonRemovableBufferChunkSizeTooLow
PHPUnit\Framework\Exception: Tests with non-removable output buffer handlers must not call flush on them and the chunk size must be bigger than the expected output

--

There were 4 risky tests:

1) PHPUnit\TestFixture\Issue5851Test::testNonClosedBufferShouldntBeIgnored
Test code or tested code did not close its own output buffers

%s%eIssue5851Test.php:%i

2) PHPUnit\TestFixture\Issue5851Test::testNonClosedBufferShouldntBeIgnored2
Test code or tested code did not close its own output buffers

%s%eIssue5851Test.php:%i

3) PHPUnit\TestFixture\Issue5851Test::testNonRemovableBufferSeparateProcess
Non-removable output handler callback was not called, which could alter output

%s%eIssue5851Test.php:%i

4) PHPUnit\TestFixture\Issue5851Test::testNonRemovableBufferSeparateProcessAgain
Non-removable output handler callback was not called, which could alter output

%s%eIssue5851Test.php:%i

FAILURES!
Tests: 14, Assertions: 14, Failures: 10, Risky: 4.
Loading