247 lines
6.5 KiB
PHP
Executable File
247 lines
6.5 KiB
PHP
Executable File
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace NunoMaduro\Collision\Adapters\Phpunit;
|
|
|
|
use NunoMaduro\Collision\Exceptions\ShouldNotHappen;
|
|
use PHPUnit\Framework\AssertionFailedError;
|
|
use PHPUnit\Framework\Test;
|
|
use PHPUnit\Framework\TestCase;
|
|
use PHPUnit\Framework\TestSuite;
|
|
use PHPUnit\Framework\Warning;
|
|
use ReflectionObject;
|
|
use Symfony\Component\Console\Input\ArgvInput;
|
|
use Symfony\Component\Console\Output\ConsoleOutput;
|
|
use Throwable;
|
|
|
|
/**
|
|
* @internal
|
|
*/
|
|
final class Printer implements \PHPUnit\TextUI\ResultPrinter
|
|
{
|
|
/**
|
|
* Holds an instance of the style.
|
|
*
|
|
* Style is a class we use to interact with output.
|
|
*
|
|
* @var Style
|
|
*/
|
|
private $style;
|
|
|
|
/**
|
|
* Holds the duration time of the test suite.
|
|
*
|
|
* @var Timer
|
|
*/
|
|
private $timer;
|
|
|
|
/**
|
|
* Holds the state of the test
|
|
* suite. The number of tests, etc.
|
|
*
|
|
* @var State
|
|
*/
|
|
private $state;
|
|
|
|
/**
|
|
* If the test suite has failed.
|
|
*
|
|
* @var bool
|
|
*/
|
|
private $failed = false;
|
|
|
|
/**
|
|
* Creates a new instance of the listener.
|
|
*
|
|
* @param ConsoleOutput $output
|
|
*
|
|
* @throws \ReflectionException
|
|
*/
|
|
public function __construct(\Symfony\Component\Console\Output\ConsoleOutputInterface $output = null, bool $verbose = false, string $colors = 'always')
|
|
{
|
|
$this->timer = Timer::start();
|
|
|
|
$decorated = $colors === 'always' || $colors === 'auto';
|
|
|
|
$output = $output ?? new ConsoleOutput(ConsoleOutput::VERBOSITY_NORMAL, $decorated);
|
|
|
|
ConfigureIO::of(new ArgvInput(), $output);
|
|
|
|
$this->style = new Style($output);
|
|
$dummyTest = new class() extends TestCase
|
|
{
|
|
};
|
|
|
|
$this->state = State::from($dummyTest);
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
public function addError(Test $testCase, Throwable $throwable, float $time): void
|
|
{
|
|
$this->failed = true;
|
|
|
|
$testCase = $this->testCaseFromTest($testCase);
|
|
|
|
$this->state->add(TestResult::fromTestCase($testCase, TestResult::FAIL, $throwable));
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
public function addWarning(Test $testCase, Warning $warning, float $time): void
|
|
{
|
|
$testCase = $this->testCaseFromTest($testCase);
|
|
|
|
$this->state->add(TestResult::fromTestCase($testCase, TestResult::WARN, $warning));
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
public function addFailure(Test $testCase, AssertionFailedError $error, float $time): void
|
|
{
|
|
$this->failed = true;
|
|
|
|
$testCase = $this->testCaseFromTest($testCase);
|
|
|
|
$reflector = new ReflectionObject($error);
|
|
|
|
if ($reflector->hasProperty('message')) {
|
|
$message = trim((string) preg_replace("/\r|\n/", "\n ", $error->getMessage()));
|
|
$property = $reflector->getProperty('message');
|
|
$property->setAccessible(true);
|
|
$property->setValue($error, $message);
|
|
}
|
|
|
|
$this->state->add(TestResult::fromTestCase($testCase, TestResult::FAIL, $error));
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
public function addIncompleteTest(Test $testCase, Throwable $throwable, float $time): void
|
|
{
|
|
$testCase = $this->testCaseFromTest($testCase);
|
|
|
|
$this->state->add(TestResult::fromTestCase($testCase, TestResult::INCOMPLETE, $throwable));
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
public function addRiskyTest(Test $testCase, Throwable $throwable, float $time): void
|
|
{
|
|
$testCase = $this->testCaseFromTest($testCase);
|
|
|
|
$this->state->add(TestResult::fromTestCase($testCase, TestResult::RISKY, $throwable));
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
public function addSkippedTest(Test $testCase, Throwable $throwable, float $time): void
|
|
{
|
|
$testCase = $this->testCaseFromTest($testCase);
|
|
|
|
$this->state->add(TestResult::fromTestCase($testCase, TestResult::SKIPPED, $throwable));
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
public function startTestSuite(TestSuite $suite): void
|
|
{
|
|
if ($this->state->suiteTotalTests === null) {
|
|
$this->state->suiteTotalTests = $suite->count();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
public function endTestSuite(TestSuite $suite): void
|
|
{
|
|
// ..
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
public function startTest(Test $testCase): void
|
|
{
|
|
$testCase = $this->testCaseFromTest($testCase);
|
|
|
|
// Let's check first if the testCase is over.
|
|
if ($this->state->testCaseHasChanged($testCase)) {
|
|
$this->style->writeCurrentTestCaseSummary($this->state);
|
|
|
|
$this->state->moveTo($testCase);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
public function endTest(Test $testCase, float $time): void
|
|
{
|
|
$testCase = $this->testCaseFromTest($testCase);
|
|
|
|
if (! $this->state->existsInTestCase($testCase)) {
|
|
$this->state->add(TestResult::fromTestCase($testCase, TestResult::PASS));
|
|
}
|
|
|
|
if ($testCase instanceof TestCase
|
|
&& $testCase->getTestResultObject() instanceof \PHPUnit\Framework\TestResult
|
|
&& ! $testCase->getTestResultObject()->isStrictAboutOutputDuringTests()
|
|
&& ! $testCase->hasExpectationOnOutput()) {
|
|
$this->style->write($testCase->getActualOutput());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Intentionally left blank as we output things on events of the listener.
|
|
*/
|
|
public function write(string $content): void
|
|
{
|
|
// ..
|
|
}
|
|
|
|
/**
|
|
* Returns a test case from the given test.
|
|
*
|
|
* Note: This printer is do not work with normal Test classes - only
|
|
* with Test Case classes. Please report an issue if you think
|
|
* this should work any other way.
|
|
*/
|
|
private function testCaseFromTest(Test $test): TestCase
|
|
{
|
|
if (! $test instanceof TestCase) {
|
|
throw new ShouldNotHappen();
|
|
}
|
|
|
|
return $test;
|
|
}
|
|
|
|
/**
|
|
* Intentionally left blank as we output things on events of the listener.
|
|
*/
|
|
public function printResult(\PHPUnit\Framework\TestResult $result): void
|
|
{
|
|
if ($result->count() === 0) {
|
|
$this->style->writeWarning('No tests executed!');
|
|
}
|
|
|
|
$this->style->writeCurrentTestCaseSummary($this->state);
|
|
|
|
if ($this->failed) {
|
|
$onFailure = $this->state->suiteTotalTests !== $this->state->testSuiteTestsCount();
|
|
$this->style->writeErrorsSummary($this->state, $onFailure);
|
|
}
|
|
|
|
$this->style->writeRecap($this->state, $this->timer);
|
|
}
|
|
}
|