mirror of
https://github.com/pestphp/pest.git
synced 2026-03-06 07:47:22 +01:00
feat: kernel dump
This commit is contained in:
17
resources/views/components/badge.php
Normal file
17
resources/views/components/badge.php
Normal file
@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
/** @var string $type */
|
||||
/** @var string $content */
|
||||
[$bgBadgeColor, $bgBadgeText] = match ($type) {
|
||||
'INFO' => ['blue', 'INFO'],
|
||||
'ERROR' => ['red', 'ERROR'],
|
||||
};
|
||||
|
||||
?>
|
||||
|
||||
<div class="my-1">
|
||||
<span class="ml-2 px-1 bg-<?php echo $bgBadgeColor ?>-600 font-bold"><?php echo htmlspecialchars($bgBadgeText) ?></span>
|
||||
<span class="ml-1">
|
||||
<?php echo htmlspecialchars($content) ?>
|
||||
</span>
|
||||
</div>
|
||||
37
src/Bootstrappers/BootKernelDump.php
Normal file
37
src/Bootstrappers/BootKernelDump.php
Normal file
@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Pest\Bootstrappers;
|
||||
|
||||
use Pest\Contracts\Bootstrapper;
|
||||
use Pest\KernelDump;
|
||||
use Pest\Support\Container;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class BootKernelDump implements Bootstrapper
|
||||
{
|
||||
/**
|
||||
* Creates a new Boot Kernel Dump instance.
|
||||
*/
|
||||
public function __construct(
|
||||
private readonly OutputInterface $output,
|
||||
) {
|
||||
// ...
|
||||
}
|
||||
|
||||
/**
|
||||
* Boots the kernel dump.
|
||||
*/
|
||||
public function boot(): void
|
||||
{
|
||||
Container::getInstance()->add(KernelDump::class, $kernelDump = new KernelDump(
|
||||
$this->output,
|
||||
));
|
||||
|
||||
$kernelDump->enable();
|
||||
}
|
||||
}
|
||||
@ -24,6 +24,7 @@ final class BootSubscribers implements Bootstrapper
|
||||
Subscribers\EnsureConfigurationIsValid::class,
|
||||
Subscribers\EnsureConfigurationIsAvailable::class,
|
||||
Subscribers\EnsureTeamCityEnabled::class,
|
||||
Subscribers\EnsureKernelDumpIsFlushed::class,
|
||||
];
|
||||
|
||||
/**
|
||||
|
||||
@ -31,6 +31,7 @@ final class Kernel
|
||||
Bootstrappers\BootSubscribers::class,
|
||||
Bootstrappers\BootFiles::class,
|
||||
Bootstrappers\BootView::class,
|
||||
Bootstrappers\BootKernelDump::class,
|
||||
];
|
||||
|
||||
/**
|
||||
@ -106,6 +107,12 @@ final class Kernel
|
||||
*/
|
||||
public function shutdown(): void
|
||||
{
|
||||
$preBufferOutput = Container::getInstance()->get(KernelDump::class);
|
||||
|
||||
assert($preBufferOutput instanceof KernelDump);
|
||||
|
||||
$preBufferOutput->shutdown();
|
||||
|
||||
CallsShutdown::execute();
|
||||
}
|
||||
}
|
||||
|
||||
91
src/KernelDump.php
Normal file
91
src/KernelDump.php
Normal file
@ -0,0 +1,91 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Pest;
|
||||
|
||||
use Pest\Support\View;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
final class KernelDump
|
||||
{
|
||||
/**
|
||||
* The output buffer, if any.
|
||||
*/
|
||||
private string $buffer = '';
|
||||
|
||||
/**
|
||||
* Creates a new Kernel Dump instance.
|
||||
*/
|
||||
public function __construct(
|
||||
private readonly OutputInterface $output,
|
||||
) {
|
||||
// ...
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable the output buffering.
|
||||
*/
|
||||
public function enable(): void
|
||||
{
|
||||
ob_start(function (string $message): string {
|
||||
$this->buffer .= $message;
|
||||
|
||||
return '';
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable the output buffering.
|
||||
*/
|
||||
public function disable(): void
|
||||
{
|
||||
ob_clean();
|
||||
|
||||
if ($this->buffer !== '') {
|
||||
$this->flush('INFO');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shutdown the output buffering.
|
||||
*/
|
||||
public function shutdown(): void
|
||||
{
|
||||
ob_clean();
|
||||
|
||||
if ($this->buffer !== '') {
|
||||
$this->flush('ERROR');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Flushes the buffer.
|
||||
*/
|
||||
private function flush(string $type): void
|
||||
{
|
||||
View::renderUsing($this->output);
|
||||
|
||||
if ($this->isOpeningHeadline($this->buffer)) {
|
||||
$this->buffer = implode(PHP_EOL, array_slice(explode(PHP_EOL, $this->buffer), 2));
|
||||
}
|
||||
|
||||
$this->buffer = trim($this->buffer);
|
||||
$this->buffer = rtrim($this->buffer, '.').'.';
|
||||
|
||||
View::render('components.badge', [
|
||||
'type' => $type,
|
||||
'content' => $this->buffer,
|
||||
]);
|
||||
|
||||
$this->buffer = '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given output contains an opening headline.
|
||||
*/
|
||||
private function isOpeningHeadline(string $output): bool
|
||||
{
|
||||
return str_contains($output, 'by Sebastian Bergmann and contributors.');
|
||||
}
|
||||
}
|
||||
@ -101,15 +101,15 @@ final class Help implements HandlesArguments
|
||||
]] + $content['Configuration'];
|
||||
|
||||
$content['Selection'] = [
|
||||
[
|
||||
'arg' => '--todos',
|
||||
'desc' => 'Output to standard output the list of todos',
|
||||
],
|
||||
[
|
||||
'arg' => '--retry',
|
||||
'desc' => 'Run non-passing tests first and stop execution upon first error or failure',
|
||||
],
|
||||
] + $content['Selection'];
|
||||
[
|
||||
'arg' => '--todos',
|
||||
'desc' => 'Output to standard output the list of todos',
|
||||
],
|
||||
[
|
||||
'arg' => '--retry',
|
||||
'desc' => 'Run non-passing tests first and stop execution upon first error or failure',
|
||||
],
|
||||
] + $content['Selection'];
|
||||
|
||||
$content['Code Coverage'] = [
|
||||
[
|
||||
@ -123,11 +123,11 @@ final class Help implements HandlesArguments
|
||||
] + $content['Code Coverage'];
|
||||
|
||||
$content['Profiling'] = [
|
||||
[
|
||||
'arg' => '--profile ',
|
||||
'desc' => 'Output to standard output the top ten slowest tests',
|
||||
],
|
||||
];
|
||||
[
|
||||
'arg' => '--profile ',
|
||||
'desc' => 'Output to standard output the top ten slowest tests',
|
||||
],
|
||||
];
|
||||
|
||||
unset($content['Miscellaneous']);
|
||||
|
||||
|
||||
@ -5,7 +5,6 @@ declare(strict_types=1);
|
||||
namespace Pest\Plugins;
|
||||
|
||||
use ParaTest\ParaTestCommand;
|
||||
use Pest\Contracts\Plugins\AddsOutput;
|
||||
use Pest\Contracts\Plugins\HandlesArguments;
|
||||
use Pest\Plugins\Actions\CallsAddsOutput;
|
||||
use Pest\Plugins\Concerns\HandleArguments;
|
||||
|
||||
28
src/Subscribers/EnsureKernelDumpIsFlushed.php
Normal file
28
src/Subscribers/EnsureKernelDumpIsFlushed.php
Normal file
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Pest\Subscribers;
|
||||
|
||||
use Pest\KernelDump;
|
||||
use Pest\Support\Container;
|
||||
use PHPUnit\Event\TestRunner\Started;
|
||||
use PHPUnit\Event\TestRunner\StartedSubscriber;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class EnsureKernelDumpIsFlushed implements StartedSubscriber
|
||||
{
|
||||
/**
|
||||
* Runs the subscriber.
|
||||
*/
|
||||
public function notify(Started $event): void
|
||||
{
|
||||
$kernelDump = Container::getInstance()->get(KernelDump::class);
|
||||
|
||||
assert($kernelDump instanceof KernelDump);
|
||||
|
||||
$kernelDump->disable();
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,6 @@
|
||||
##teamcity[testSuiteStarted name='Tests/tests/Failure' locationHint='file://tests/.tests/Failure.php' flowId='1234']
|
||||
##teamcity[testStarted name='it can fail with comparison' locationHint='pest_qn://tests/.tests/Failure.php::it can fail with comparison' flowId='1234']
|
||||
##teamcity[testFailed name='it can fail with comparison' message='Failed asserting that true matches expected false.' details='at src/Mixins/Expectation.php:342|nat src/Support/ExpectationPipeline.php:75|nat src/Support/ExpectationPipeline.php:79|nat src/Expectation.php:300|nat tests/.tests/Failure.php:6|nat src/Factories/TestCaseMethodFactory.php:100|nat src/Concerns/Testable.php:262|nat src/Support/ExceptionTrace.php:28|nat src/Concerns/Testable.php:262|nat src/Concerns/Testable.php:217|nat src/Kernel.php:89' type='comparisonFailure' actual='true' expected='false' flowId='1234']
|
||||
##teamcity[testFailed name='it can fail with comparison' message='Failed asserting that true matches expected false.' details='at src/Mixins/Expectation.php:342|nat src/Support/ExpectationPipeline.php:75|nat src/Support/ExpectationPipeline.php:79|nat src/Expectation.php:300|nat tests/.tests/Failure.php:6|nat src/Factories/TestCaseMethodFactory.php:100|nat src/Concerns/Testable.php:262|nat src/Support/ExceptionTrace.php:28|nat src/Concerns/Testable.php:262|nat src/Concerns/Testable.php:217|nat src/Kernel.php:91' type='comparisonFailure' actual='true' expected='false' flowId='1234']
|
||||
##teamcity[testFinished name='it can fail with comparison' duration='100000' flowId='1234']
|
||||
##teamcity[testStarted name='it can be ignored because of no assertions' locationHint='pest_qn://tests/.tests/Failure.php::it can be ignored because of no assertions' flowId='1234']
|
||||
##teamcity[testIgnored name='it can be ignored because of no assertions' message='This test did not perform any assertions' details='' flowId='1234']
|
||||
@ -9,7 +9,7 @@
|
||||
##teamcity[testIgnored name='it can be ignored because it is skipped' message='This test was ignored.' details='' flowId='1234']
|
||||
##teamcity[testFinished name='it can be ignored because it is skipped' duration='100000' flowId='1234']
|
||||
##teamcity[testStarted name='it can fail' locationHint='pest_qn://tests/.tests/Failure.php::it can fail' flowId='1234']
|
||||
##teamcity[testFailed name='it can fail' message='oh noo' details='at tests/.tests/Failure.php:18|nat src/Factories/TestCaseMethodFactory.php:100|nat src/Concerns/Testable.php:262|nat src/Support/ExceptionTrace.php:28|nat src/Concerns/Testable.php:262|nat src/Concerns/Testable.php:217|nat src/Kernel.php:89' flowId='1234']
|
||||
##teamcity[testFailed name='it can fail' message='oh noo' details='at tests/.tests/Failure.php:18|nat src/Factories/TestCaseMethodFactory.php:100|nat src/Concerns/Testable.php:262|nat src/Support/ExceptionTrace.php:28|nat src/Concerns/Testable.php:262|nat src/Concerns/Testable.php:217|nat src/Kernel.php:91' flowId='1234']
|
||||
##teamcity[testFinished name='it can fail' duration='100000' flowId='1234']
|
||||
##teamcity[testStarted name='it is not done yet' locationHint='pest_qn://tests/.tests/Failure.php::it is not done yet' flowId='1234']
|
||||
##teamcity[testIgnored name='it is not done yet' message='This test was ignored.' details='' flowId='1234']
|
||||
|
||||
@ -15,8 +15,8 @@
|
||||
--migrate-configuration ....... Migrate configuration file to current format
|
||||
|
||||
SELECTION OPTIONS:
|
||||
--list-suites ................................... List available test suites
|
||||
--testsuite <name> ............... Only run tests from the specified test suite(s)
|
||||
--todos ........................ Output to standard output the list of todos
|
||||
--retry Run non-passing tests first and stop execution upon first error or failure
|
||||
--exclude-testsuite <name> ........ Exclude tests from the specified test suite(s)
|
||||
--list-groups ................................... List available test groups
|
||||
--group <name> ........................ Only run tests from the specified group(s)
|
||||
@ -95,9 +95,6 @@
|
||||
--disable-coverage-ignore Disable attributes and annotations for ignoring code coverage
|
||||
--no-coverage ........................... Ignore code coverage configuration
|
||||
|
||||
MISCELLANEOUS OPTIONS:
|
||||
-h|--help .................................... Prints this usage information
|
||||
--version ..................................... Prints the version and exits
|
||||
--atleast-version <min> ....... Checks that version is greater than min and exits
|
||||
--check-version ................ Check whether PHPUnit is the latest version
|
||||
PROFILING OPTIONS:
|
||||
--profile .............. Output to standard output the top ten slowest tests
|
||||
|
||||
|
||||
Reference in New Issue
Block a user