feat: kernel dump

This commit is contained in:
Nuno Maduro
2023-02-18 14:39:44 +00:00
parent d0e949bf19
commit 7fc12613a8
10 changed files with 201 additions and 24 deletions

View 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>

View 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();
}
}

View File

@ -24,6 +24,7 @@ final class BootSubscribers implements Bootstrapper
Subscribers\EnsureConfigurationIsValid::class,
Subscribers\EnsureConfigurationIsAvailable::class,
Subscribers\EnsureTeamCityEnabled::class,
Subscribers\EnsureKernelDumpIsFlushed::class,
];
/**

View File

@ -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
View 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.');
}
}

View File

@ -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']);

View File

@ -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;

View 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();
}
}

View File

@ -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']

View File

@ -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