From ac33d93f407876411384e73d5d5d90ffac57f8d8 Mon Sep 17 00:00:00 2001 From: Lasse Foo-Rafn Date: Mon, 9 Sep 2024 17:41:21 +0200 Subject: [PATCH 01/14] Create Logger.php base --- src/Contracts/Logger.php | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 src/Contracts/Logger.php diff --git a/src/Contracts/Logger.php b/src/Contracts/Logger.php new file mode 100644 index 0000000..3879f95 --- /dev/null +++ b/src/Contracts/Logger.php @@ -0,0 +1,27 @@ + $pluginSettings + */ + public function __construct( string $outputPath, array $pluginSettings ); + + /** + * @param array $uncoveredLines + * @param array $uncoveredLinesIgnored + */ + public function append(string $path, array $uncoveredLines, array $uncoveredLinesIgnored, float $percentage):void; + + public function output():void; + } From bf0488dc4ce7d252f9bcb27f2a02846302422455 Mon Sep 17 00:00:00 2001 From: Lasse Foo-Rafn Date: Mon, 9 Sep 2024 17:42:47 +0200 Subject: [PATCH 02/14] Create JsonLogger.php base --- src/Logging/JsonLogger.php | 49 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 src/Logging/JsonLogger.php diff --git a/src/Logging/JsonLogger.php b/src/Logging/JsonLogger.php new file mode 100644 index 0000000..155996b --- /dev/null +++ b/src/Logging/JsonLogger.php @@ -0,0 +1,49 @@ + */ + private array $pluginSettings; + + /** @var array>> */ + private array $logs = []; + + public function __construct( string $outputPath, array $pluginSettings ) { + $this->outputPath = $outputPath; + $this->pluginSettings = $pluginSettings; + } + + public function append(string $path, array $uncoveredLines, array $uncoveredLinesIgnored, float $percentage):void + { + $this->logs[] = [ + 'file' => $path, + 'uncoveredLines' => $uncoveredLines, + 'uncoveredLinesIgnored' => $uncoveredLinesIgnored, + 'percentage' => $percentage, + ]; + } + + public function output(): void + { + $json = json_encode( [ + 'format' => 'pest', + 'settings' => $this->pluginSettings, + 'result' => $this->logs, + 'total' => round( array_sum(array_column($this->logs, 'percentage')) / count($this->logs), 2 ) + ], JSON_THROW_ON_ERROR ); + file_put_contents($this->outputPath, $json); + } +} From dafe6bf2dd01b4a34bd520ee088cf9dadc0fe340 Mon Sep 17 00:00:00 2001 From: Lasse Foo-Rafn Date: Mon, 9 Sep 2024 17:43:12 +0200 Subject: [PATCH 03/14] Create NullLogger.php base --- src/Logging/NullLogger.php | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 src/Logging/NullLogger.php diff --git a/src/Logging/NullLogger.php b/src/Logging/NullLogger.php new file mode 100644 index 0000000..8841089 --- /dev/null +++ b/src/Logging/NullLogger.php @@ -0,0 +1,34 @@ + $pluginSettings + */ + public function __construct( string $outputPath, array $pluginSettings ) + { + // + } + + public function append(string $path, array $uncoveredLines, array $uncoveredLinesIgnored, float $percentage):void + { + // + } + + public function output(): void + { + // + } +} From d2a9f2ff54230c68251963bfe8f77bf60d78b3ac Mon Sep 17 00:00:00 2001 From: Lasse Foo-Rafn Date: Mon, 9 Sep 2024 17:53:32 +0200 Subject: [PATCH 04/14] Create JsonPrinter.php --- src/Support/Printers/JsonPrinter.php | 267 +++++++++++++++++++++++++++ 1 file changed, 267 insertions(+) create mode 100644 src/Support/Printers/JsonPrinter.php diff --git a/src/Support/Printers/JsonPrinter.php b/src/Support/Printers/JsonPrinter.php new file mode 100644 index 0000000..01d07fc --- /dev/null +++ b/src/Support/Printers/JsonPrinter.php @@ -0,0 +1,267 @@ +compact = true; + } + + public function reportTestedMutation(MutationTest $test): void + { + if ($this->compact) { + $this->output->write('.'); + + return; + } + + $this->writeMutationTestLine('green', '✓', $test); + } + + public function reportUntestedMutation(MutationTest $test): void + { + if ($this->compact) { + $this->output->write('x'); + + return; + } + + $this->writeMutationTestLine('red', '⨯', $test); + } + + public function reportUncoveredMutation(MutationTest $test): void + { + if ($this->compact) { + $this->output->write('-'); + + return; + } + + $this->writeMutationTestLine('yellow', '-', $test); + } + + public function reportTimedOutMutation(MutationTest $test): void + { + if ($this->compact) { + $this->output->write('t'); + + return; + } + + $this->writeMutationTestLine('yellow', 't', $test); + } + + public function printFilename(MutationTestCollection $testCollection): void + { + if ($this->compact) { + return; + } + + $path = str_ireplace(getcwd().'/', '', $testCollection->file->getRealPath()); + + $this->output->writeln(''); + $this->output->writeln(' RUN '.$path); + } + + public function reportError(string $message): void + { + $this->output->writeln([ + '', + ' ERROR '.$message.'', + '', + ]); + } + + public function reportScoreNotReached(float $scoreReached, float $scoreRequired): void + { + $this->output->writeln([ + ' FAIL Mutation score below expected: '.number_format($scoreReached, 1).' %. Minimum: '.number_format($scoreRequired, 1).' %.', + '', + ]); + } + + public function reportMutationGenerationStarted(MutationSuite $mutationSuite): void + { + $this->output->writeln(' Mutating application files...'); + } + + public function reportMutationGenerationFinished(MutationSuite $mutationSuite): void + { + $this->output->writeln([ + ' '.$mutationSuite->repository->total().' Mutations for '.$mutationSuite->repository->count().' Files created', + ]); + } + + public function reportMutationSuiteStarted(MutationSuite $mutationSuite): void + { + if ($this->compact) { + $this->output->writeln(''); + $this->output->write(' '); // ensure proper indentation before compact test output + } + } + + public function reportMutationSuiteFinished(MutationSuite $mutationSuite): void + { + /** @var Configuration $configuration */ + $configuration = Container::getInstance()->get(ConfigurationRepository::class)->mergedConfiguration(); // @phpstan-ignore-line + + if ($this->compact) { + $this->output->writeln(''); // add new line after compact test output + } + + $this->writeMutationSuiteSummary($mutationSuite); + + $this->output->writeln([ + ' Mutations: '.($mutationSuite->repository->untested() !== 0 ? ''.$mutationSuite->repository->untested().' untested, ' : '').($mutationSuite->repository->uncovered() !== 0 ? ''.$mutationSuite->repository->uncovered().' uncovered, ' : '').($mutationSuite->repository->notRun() !== 0 ? ''.$mutationSuite->repository->notRun().' pending, ' : '').($mutationSuite->repository->timedOut() !== 0 ? ''.$mutationSuite->repository->timedOut().' timeout, ' : '').''.$mutationSuite->repository->tested().' tested', + ]); + + $score = number_format($mutationSuite->score(), 2); + $this->output->writeln(' Score: minScoreReached() ? 'default' : 'red').'>'.$score.'%'); + + $duration = number_format($mutationSuite->duration(), 2); + $this->output->writeln(' Duration: '.$duration.'s'); + + if ($configuration->parallel) { + $processes = $configuration->processes; + $this->output->writeln(' Parallel: '.$processes.' processes'); + } + + if ($mutationSuite->repository->count() === 0) { + $this->output->writeln([ + '', + ' INFO No mutations created.', + '', + ]); + + return; + } + + $this->output->writeln(''); + + if ($configuration->profile) { + $this->writeMutationTestProfile($mutationSuite); + } + } + + private function writeMutationTestLine(string $color, string $symbol, MutationTest $test): void + { + $this->output->writeln(' '.$symbol.' Line '.$test->mutation->startLine.': '.$test->mutation->mutator::name().''); // @pest-mutate-ignore + } + + private function writeMutationSuiteSummary(MutationSuite $mutationSuite): void + { + foreach ($mutationSuite->repository->all() as $testCollection) { + foreach ($testCollection->tests() as $test) { + $this->writeMutationTestSummary($test); + } + } + } + + private function writeMutationTestSummary(MutationTest $test): void + { + if (! in_array($test->result(), [MutationTestResult::Untested, MutationTestResult::Uncovered], true)) { + return; + } + + $path = str_ireplace(getcwd().'/', '', $test->mutation->file->getRealPath()); + + render(<<<'HTML' +
+ +
+ HTML + ); + + if ($test->result() === MutationTestResult::Untested) { + $color = 'red'; + $label = 'UNTESTED'; + } else { + $color = 'bright-red'; + $label = 'UNCOVERED'; + } + + $this->output->writeln([ + ' '.$label.' '.$path.' > Line '.$test->mutation->startLine.': '.$test->mutation->mutator::name().' - ID: '.$test->getId().'', // @pest-mutate-ignore + ]); + + $diff = $test->mutation->diff; + $this->output->writeln($diff); + } + + private function writeMutationTestProfile(MutationSuite $mutationSuite): void + { + /** @var Configuration $configuration */ + $configuration = Container::getInstance()->get(ConfigurationRepository::class)->mergedConfiguration(); // @phpstan-ignore-line + + $this->output->writeln(' Top 10 slowest mutation tests:'); + + $timeElapsed = $mutationSuite->duration() * ($configuration->parallel ? $configuration->processes : 1); + + $slowTests = $mutationSuite->repository->slowest(); + + foreach ($slowTests as $slowTest) { + $path = str_ireplace(getcwd().'/', '', (string) $slowTest->mutation->file->getRealPath()); + + $seconds = number_format($slowTest->duration(), 2, '.', ''); + + $color = ($slowTest->duration()) > $timeElapsed * 0.25 ? 'red' : ($slowTest->duration() > $timeElapsed * 0.1 ? 'yellow' : 'gray'); + + render(sprintf(<<<'HTML' +
+ + %s>Line %s: %s - ID: %s + + + %ss + +
+ HTML, $path, $slowTest->mutation->startLine, $slowTest->mutation->mutator::name(), $slowTest->getId(), $color, $seconds)); + } + + $timeElapsedInSlowTests = array_sum(array_map(fn (MutationTest $testResult): float => $testResult->duration(), $slowTests)); + + $timeElapsedAsString = number_format($timeElapsed, 2, '.', ''); + $percentageInSlowTestsAsString = number_format($timeElapsedInSlowTests * 100 / $timeElapsed, 2, '.', ''); + $timeElapsedInSlowTestsAsString = number_format($timeElapsedInSlowTests, 2, '.', ''); + + render(sprintf(<<<'HTML' +
+
+
+
+
+ + + + (%s%% of %ss) + %ss + +
+
+ HTML, $percentageInSlowTestsAsString, $timeElapsedAsString, $timeElapsedInSlowTestsAsString)); + } +} From 5ad71403d7318fd99694a6a0492173e295ce4377 Mon Sep 17 00:00:00 2001 From: Lasse Foo-Rafn Date: Mon, 9 Sep 2024 17:54:00 +0200 Subject: [PATCH 05/14] Delete src/Support/Printers/JsonPrinter.php --- src/Support/Printers/JsonPrinter.php | 267 --------------------------- 1 file changed, 267 deletions(-) delete mode 100644 src/Support/Printers/JsonPrinter.php diff --git a/src/Support/Printers/JsonPrinter.php b/src/Support/Printers/JsonPrinter.php deleted file mode 100644 index 01d07fc..0000000 --- a/src/Support/Printers/JsonPrinter.php +++ /dev/null @@ -1,267 +0,0 @@ -compact = true; - } - - public function reportTestedMutation(MutationTest $test): void - { - if ($this->compact) { - $this->output->write('.'); - - return; - } - - $this->writeMutationTestLine('green', '✓', $test); - } - - public function reportUntestedMutation(MutationTest $test): void - { - if ($this->compact) { - $this->output->write('x'); - - return; - } - - $this->writeMutationTestLine('red', '⨯', $test); - } - - public function reportUncoveredMutation(MutationTest $test): void - { - if ($this->compact) { - $this->output->write('-'); - - return; - } - - $this->writeMutationTestLine('yellow', '-', $test); - } - - public function reportTimedOutMutation(MutationTest $test): void - { - if ($this->compact) { - $this->output->write('t'); - - return; - } - - $this->writeMutationTestLine('yellow', 't', $test); - } - - public function printFilename(MutationTestCollection $testCollection): void - { - if ($this->compact) { - return; - } - - $path = str_ireplace(getcwd().'/', '', $testCollection->file->getRealPath()); - - $this->output->writeln(''); - $this->output->writeln(' RUN '.$path); - } - - public function reportError(string $message): void - { - $this->output->writeln([ - '', - ' ERROR '.$message.'', - '', - ]); - } - - public function reportScoreNotReached(float $scoreReached, float $scoreRequired): void - { - $this->output->writeln([ - ' FAIL Mutation score below expected: '.number_format($scoreReached, 1).' %. Minimum: '.number_format($scoreRequired, 1).' %.', - '', - ]); - } - - public function reportMutationGenerationStarted(MutationSuite $mutationSuite): void - { - $this->output->writeln(' Mutating application files...'); - } - - public function reportMutationGenerationFinished(MutationSuite $mutationSuite): void - { - $this->output->writeln([ - ' '.$mutationSuite->repository->total().' Mutations for '.$mutationSuite->repository->count().' Files created', - ]); - } - - public function reportMutationSuiteStarted(MutationSuite $mutationSuite): void - { - if ($this->compact) { - $this->output->writeln(''); - $this->output->write(' '); // ensure proper indentation before compact test output - } - } - - public function reportMutationSuiteFinished(MutationSuite $mutationSuite): void - { - /** @var Configuration $configuration */ - $configuration = Container::getInstance()->get(ConfigurationRepository::class)->mergedConfiguration(); // @phpstan-ignore-line - - if ($this->compact) { - $this->output->writeln(''); // add new line after compact test output - } - - $this->writeMutationSuiteSummary($mutationSuite); - - $this->output->writeln([ - ' Mutations: '.($mutationSuite->repository->untested() !== 0 ? ''.$mutationSuite->repository->untested().' untested, ' : '').($mutationSuite->repository->uncovered() !== 0 ? ''.$mutationSuite->repository->uncovered().' uncovered, ' : '').($mutationSuite->repository->notRun() !== 0 ? ''.$mutationSuite->repository->notRun().' pending, ' : '').($mutationSuite->repository->timedOut() !== 0 ? ''.$mutationSuite->repository->timedOut().' timeout, ' : '').''.$mutationSuite->repository->tested().' tested', - ]); - - $score = number_format($mutationSuite->score(), 2); - $this->output->writeln(' Score: minScoreReached() ? 'default' : 'red').'>'.$score.'%'); - - $duration = number_format($mutationSuite->duration(), 2); - $this->output->writeln(' Duration: '.$duration.'s'); - - if ($configuration->parallel) { - $processes = $configuration->processes; - $this->output->writeln(' Parallel: '.$processes.' processes'); - } - - if ($mutationSuite->repository->count() === 0) { - $this->output->writeln([ - '', - ' INFO No mutations created.', - '', - ]); - - return; - } - - $this->output->writeln(''); - - if ($configuration->profile) { - $this->writeMutationTestProfile($mutationSuite); - } - } - - private function writeMutationTestLine(string $color, string $symbol, MutationTest $test): void - { - $this->output->writeln(' '.$symbol.' Line '.$test->mutation->startLine.': '.$test->mutation->mutator::name().''); // @pest-mutate-ignore - } - - private function writeMutationSuiteSummary(MutationSuite $mutationSuite): void - { - foreach ($mutationSuite->repository->all() as $testCollection) { - foreach ($testCollection->tests() as $test) { - $this->writeMutationTestSummary($test); - } - } - } - - private function writeMutationTestSummary(MutationTest $test): void - { - if (! in_array($test->result(), [MutationTestResult::Untested, MutationTestResult::Uncovered], true)) { - return; - } - - $path = str_ireplace(getcwd().'/', '', $test->mutation->file->getRealPath()); - - render(<<<'HTML' -
- -
- HTML - ); - - if ($test->result() === MutationTestResult::Untested) { - $color = 'red'; - $label = 'UNTESTED'; - } else { - $color = 'bright-red'; - $label = 'UNCOVERED'; - } - - $this->output->writeln([ - ' '.$label.' '.$path.' > Line '.$test->mutation->startLine.': '.$test->mutation->mutator::name().' - ID: '.$test->getId().'', // @pest-mutate-ignore - ]); - - $diff = $test->mutation->diff; - $this->output->writeln($diff); - } - - private function writeMutationTestProfile(MutationSuite $mutationSuite): void - { - /** @var Configuration $configuration */ - $configuration = Container::getInstance()->get(ConfigurationRepository::class)->mergedConfiguration(); // @phpstan-ignore-line - - $this->output->writeln(' Top 10 slowest mutation tests:'); - - $timeElapsed = $mutationSuite->duration() * ($configuration->parallel ? $configuration->processes : 1); - - $slowTests = $mutationSuite->repository->slowest(); - - foreach ($slowTests as $slowTest) { - $path = str_ireplace(getcwd().'/', '', (string) $slowTest->mutation->file->getRealPath()); - - $seconds = number_format($slowTest->duration(), 2, '.', ''); - - $color = ($slowTest->duration()) > $timeElapsed * 0.25 ? 'red' : ($slowTest->duration() > $timeElapsed * 0.1 ? 'yellow' : 'gray'); - - render(sprintf(<<<'HTML' -
- - %s>Line %s: %s - ID: %s - - - %ss - -
- HTML, $path, $slowTest->mutation->startLine, $slowTest->mutation->mutator::name(), $slowTest->getId(), $color, $seconds)); - } - - $timeElapsedInSlowTests = array_sum(array_map(fn (MutationTest $testResult): float => $testResult->duration(), $slowTests)); - - $timeElapsedAsString = number_format($timeElapsed, 2, '.', ''); - $percentageInSlowTestsAsString = number_format($timeElapsedInSlowTests * 100 / $timeElapsed, 2, '.', ''); - $timeElapsedInSlowTestsAsString = number_format($timeElapsedInSlowTests, 2, '.', ''); - - render(sprintf(<<<'HTML' -
-
-
-
-
- - - - (%s%% of %ss) - %ss - -
-
- HTML, $percentageInSlowTestsAsString, $timeElapsedAsString, $timeElapsedInSlowTestsAsString)); - } -} From 52d446d80046b91833aa9f969fee8267927890d1 Mon Sep 17 00:00:00 2001 From: Lasse Foo-Rafn Date: Mon, 9 Sep 2024 18:03:22 +0200 Subject: [PATCH 06/14] Update Mutate.php --- src/Plugins/Mutate.php | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/Plugins/Mutate.php b/src/Plugins/Mutate.php index 56c3e1f..7c60d26 100644 --- a/src/Plugins/Mutate.php +++ b/src/Plugins/Mutate.php @@ -44,6 +44,9 @@ use Pest\Support\Coverage; use Psr\SimpleCache\CacheInterface; use Symfony\Component\Console\Output\OutputInterface; +use Pest\Mutate\Logging\JsonLogger; +use Pest\Mutate\Contracts\Logger; +use Pest\Mutate\Logging\NullLogger; /** * @internal @@ -57,6 +60,11 @@ class Mutate implements AddsOutput, Bootable, HandlesArguments final public const ENV_MUTATION_TESTING = 'PEST_MUTATION_TESTING'; final public const ENV_MUTATION_FILE = 'PEST_MUTATION_FILE'; + + /** + * The logger used to output mutation metrics to a file. + */ + private Logger $logger; /** * The Kernel bootstrappers. @@ -75,7 +83,7 @@ public function __construct( private readonly Container $container, private readonly OutputInterface $output, ) { - // + $this->logger = new NullLogger('', []); } public function boot(): void @@ -130,6 +138,10 @@ public function handleArguments(array $arguments): array } else { $arguments[] = '--coverage-php='.Coverage::getPath(); } + + if ($this->hasArgument('--output-json', $arguments)) { + $this->logger = new JsonLogger(explode('=', array_flip($arguments)['--output-json'])[1], ['test' => true]); + } $arguments = Container::getInstance()->get(ConfigurationRepository::class) // @phpstan-ignore-line ->cliConfiguration->fromArguments($arguments); @@ -199,6 +211,7 @@ private function ensurePrinterIsRegistered(): void { public function notify(BeforeFirstTestExecuted $event): void { + $this->logger->a($event); $this->printer()->printFilename($event->testCollection); } }, @@ -208,6 +221,7 @@ public function notify(BeforeFirstTestExecuted $event): void { public function notify(Tested $event): void { + $this->logger->a($event); $this->printer()->reportTestedMutation($event->test); } }, @@ -216,6 +230,7 @@ public function notify(Tested $event): void { public function notify(Untested $event): void { + $this->logger->a($event); $this->printer()->reportUntestedMutation($event->test); } }, @@ -224,6 +239,7 @@ public function notify(Untested $event): void { public function notify(Timeout $event): void { + $this->logger->a($event); $this->printer()->reportTimedOutMutation($event->test); } }, @@ -232,6 +248,7 @@ public function notify(Timeout $event): void { public function notify(Uncovered $event): void { + $this->logger->a($event); $this->printer()->reportUncoveredMutation($event->test); } }, @@ -241,6 +258,7 @@ public function notify(Uncovered $event): void { public function notify(StartMutationGeneration $event): void { + $this->logger->a($event); $this->printer()->reportMutationGenerationStarted($event->mutationSuite); } }, @@ -249,6 +267,7 @@ public function notify(StartMutationGeneration $event): void { public function notify(FinishMutationGeneration $event): void { + $this->logger->a($event); $this->printer()->reportMutationGenerationFinished($event->mutationSuite); } }, @@ -257,6 +276,7 @@ public function notify(FinishMutationGeneration $event): void { public function notify(StartMutationSuite $event): void { + $this->logger->a($event); $this->printer()->reportMutationSuiteStarted($event->mutationSuite); } }, @@ -265,6 +285,7 @@ public function notify(StartMutationSuite $event): void { public function notify(FinishMutationSuite $event): void { + $this->logger->a($event); $this->printer()->reportMutationSuiteFinished($event->mutationSuite); } }, From 9f1b69701eddc7cea92bc27bca979c81baca559f Mon Sep 17 00:00:00 2001 From: lasserafn Date: Mon, 9 Sep 2024 18:13:43 +0200 Subject: [PATCH 07/14] Prepare subscription --- src/Plugins/Mutate.php | 54 +++++++++--- src/Subscribers/LoggerSubscriber.php | 20 +++++ tests/Logging/LoggingTest.php | 126 +++++++++++++++++++++++++++ 3 files changed, 189 insertions(+), 11 deletions(-) create mode 100644 src/Subscribers/LoggerSubscriber.php create mode 100644 tests/Logging/LoggingTest.php diff --git a/src/Plugins/Mutate.php b/src/Plugins/Mutate.php index 7c60d26..75a7174 100644 --- a/src/Plugins/Mutate.php +++ b/src/Plugins/Mutate.php @@ -35,6 +35,7 @@ use Pest\Mutate\Event\Events\TestSuite\StartMutationSuiteSubscriber; use Pest\Mutate\Event\Facade; use Pest\Mutate\Repositories\ConfigurationRepository; +use Pest\Mutate\Subscribers\LoggerSubscriber; use Pest\Mutate\Subscribers\PrinterSubscriber; use Pest\Mutate\Support\Printers\DefaultPrinter; use Pest\Mutate\Support\StreamWrapper; @@ -60,7 +61,7 @@ class Mutate implements AddsOutput, Bootable, HandlesArguments final public const ENV_MUTATION_TESTING = 'PEST_MUTATION_TESTING'; final public const ENV_MUTATION_FILE = 'PEST_MUTATION_FILE'; - + /** * The logger used to output mutation metrics to a file. */ @@ -138,7 +139,7 @@ public function handleArguments(array $arguments): array } else { $arguments[] = '--coverage-php='.Coverage::getPath(); } - + if ($this->hasArgument('--output-json', $arguments)) { $this->logger = new JsonLogger(explode('=', array_flip($arguments)['--output-json'])[1], ['test' => true]); } @@ -211,7 +212,6 @@ private function ensurePrinterIsRegistered(): void { public function notify(BeforeFirstTestExecuted $event): void { - $this->logger->a($event); $this->printer()->printFilename($event->testCollection); } }, @@ -221,44 +221,71 @@ public function notify(BeforeFirstTestExecuted $event): void { public function notify(Tested $event): void { - $this->logger->a($event); $this->printer()->reportTestedMutation($event->test); } }, + new class($this->logger) extends LoggerSubscriber implements TestedSubscriber + { + public function notify(Tested $event): void + { + $this->logger()->reportTestedMutation($event->test); + } + }, + new class($printer) extends PrinterSubscriber implements UntestedSubscriber { public function notify(Untested $event): void { - $this->logger->a($event); $this->printer()->reportUntestedMutation($event->test); } }, + new class($this->logger) extends LoggerSubscriber implements UntestedSubscriber + { + public function notify(Untested $event): void + { + $this->logger()->reportUntestedMutation($event->test); + } + }, + new class($printer) extends PrinterSubscriber implements TimeoutSubscriber { public function notify(Timeout $event): void { - $this->logger->a($event); $this->printer()->reportTimedOutMutation($event->test); } }, + new class($this->logger) extends LoggerSubscriber implements TimeoutSubscriber + { + public function notify(Timeout $event): void + { + $this->logger()->reportTimedOutMutation($event->test); + } + }, + new class($printer) extends PrinterSubscriber implements UncoveredSubscriber { public function notify(Uncovered $event): void { - $this->logger->a($event); $this->printer()->reportUncoveredMutation($event->test); } }, + new class($this->logger) extends LoggerSubscriber implements UncoveredSubscriber + { + public function notify(Uncovered $event): void + { + $this->logger()->reportUncoveredMutation($event->test); + } + }, + // MutationSuite new class($printer) extends PrinterSubscriber implements StartMutationGenerationSubscriber { public function notify(StartMutationGeneration $event): void { - $this->logger->a($event); $this->printer()->reportMutationGenerationStarted($event->mutationSuite); } }, @@ -267,7 +294,6 @@ public function notify(StartMutationGeneration $event): void { public function notify(FinishMutationGeneration $event): void { - $this->logger->a($event); $this->printer()->reportMutationGenerationFinished($event->mutationSuite); } }, @@ -276,7 +302,6 @@ public function notify(FinishMutationGeneration $event): void { public function notify(StartMutationSuite $event): void { - $this->logger->a($event); $this->printer()->reportMutationSuiteStarted($event->mutationSuite); } }, @@ -285,10 +310,17 @@ public function notify(StartMutationSuite $event): void { public function notify(FinishMutationSuite $event): void { - $this->logger->a($event); $this->printer()->reportMutationSuiteFinished($event->mutationSuite); } }, + + new class($this->logger) extends LoggerSubscriber implements FinishMutationSuiteSubscriber + { + public function notify(FinishMutationSuite $event): void + { + $this->logger()->reportMutationSuiteFinished($event->mutationSuite); + } + }, ]; Facade::instance()->registerSubscribers(...$subscribers); diff --git a/src/Subscribers/LoggerSubscriber.php b/src/Subscribers/LoggerSubscriber.php new file mode 100644 index 0000000..358b4de --- /dev/null +++ b/src/Subscribers/LoggerSubscriber.php @@ -0,0 +1,20 @@ +logger; + } +} diff --git a/tests/Logging/LoggingTest.php b/tests/Logging/LoggingTest.php new file mode 100644 index 0000000..fb9819d --- /dev/null +++ b/tests/Logging/LoggingTest.php @@ -0,0 +1,126 @@ + $plugin->handleArguments( [ '--type-coverage', '--type-coverage-json=test.json' ] ) )->toThrow( Exception::class, 0 ); + + expect( __DIR__ . '/../test.json' )->toBeReadableFile(); + expect( file_get_contents( __DIR__ . '/../test.json' ) )->json()->toMatchArray( [ + "format" => "pest", + 'settings' => [ + 'coverageMin' => 0, + ], + "result" => [ + [ + "file" => "src/PHPStanAnalyser.php", + "uncoveredLines" => [], + "uncoveredLinesIgnored" => [], + "percentage" => 100, + ], + [ + "file" => "src/TestCaseForTypeCoverage.php", + "uncoveredLines" => [], + "uncoveredLinesIgnored" => [], + "percentage" => 100, + ], + [ + "file" => "src/Contracts/Logger.php", + "uncoveredLines" => [], + "uncoveredLinesIgnored" => [], + "percentage" => 100, + ], + [ + "file" => "src/Plugin.php", + "uncoveredLines" => [], + "uncoveredLinesIgnored" => [], + "percentage" => 100, + ], + [ + "file" => "src/Result.php", + "uncoveredLines" => [], + "uncoveredLinesIgnored" => [], + "percentage" => 100, + ], + [ + "file" => "src/Error.php", + "uncoveredLines" => [], + "uncoveredLinesIgnored" => [], + "percentage" => 100, + ], + [ + "file" => "src/Support/ConfigurationSourceDetector.php", + "uncoveredLines" => [], + "uncoveredLinesIgnored" => [], + "percentage" => 100, + ], + [ + "file" => "src/Analyser.php", + "uncoveredLines" => [], + "uncoveredLinesIgnored" => [], + "percentage" => 100, + ], + [ + "file" => "src/Logging/NullLogger.php", + "uncoveredLines" => [], + "uncoveredLinesIgnored" => [], + "percentage" => 100, + ], + [ + "file" => "src/Logging/JsonLogger.php", + "uncoveredLines" => [], + "uncoveredLinesIgnored" => [], + "percentage" => 100, + ], + [ + "file" => "tests/Fixtures/Properties.php", + "uncoveredLines" => ["pr12"], + "uncoveredLinesIgnored" => [], + "percentage" => 83, + ], + [ + "file" => "tests/Fixtures/All.php", + "uncoveredLines" => ["pr12", "pa14", "pa14", "rt14"], + "uncoveredLinesIgnored" => [], + "percentage" => 0, + ], + [ + "file" => "tests/Fixtures/ReturnType.php", + "uncoveredLines" => ["rt12"], + "uncoveredLinesIgnored" => [], + "percentage" => 67, + ], + [ + "file" => "tests/Fixtures/Parameters.php", + "uncoveredLines" => ["pa12"], + "uncoveredLinesIgnored" => [], + "percentage" => 83, + ], + ], + 'total' => 88.07, + ]); +} ); From 04089bdc11c840ebb647396ceeca575fc6c8aa17 Mon Sep 17 00:00:00 2001 From: lasserafn Date: Mon, 9 Sep 2024 19:56:44 +0200 Subject: [PATCH 08/14] Cleanup --- src/Plugins/Mutate.php | 65 +++++++++++++++++++++--------------------- 1 file changed, 33 insertions(+), 32 deletions(-) diff --git a/src/Plugins/Mutate.php b/src/Plugins/Mutate.php index 75a7174..a5ff720 100644 --- a/src/Plugins/Mutate.php +++ b/src/Plugins/Mutate.php @@ -225,14 +225,6 @@ public function notify(Tested $event): void } }, - new class($this->logger) extends LoggerSubscriber implements TestedSubscriber - { - public function notify(Tested $event): void - { - $this->logger()->reportTestedMutation($event->test); - } - }, - new class($printer) extends PrinterSubscriber implements UntestedSubscriber { public function notify(Untested $event): void @@ -241,14 +233,6 @@ public function notify(Untested $event): void } }, - new class($this->logger) extends LoggerSubscriber implements UntestedSubscriber - { - public function notify(Untested $event): void - { - $this->logger()->reportUntestedMutation($event->test); - } - }, - new class($printer) extends PrinterSubscriber implements TimeoutSubscriber { public function notify(Timeout $event): void @@ -257,14 +241,6 @@ public function notify(Timeout $event): void } }, - new class($this->logger) extends LoggerSubscriber implements TimeoutSubscriber - { - public function notify(Timeout $event): void - { - $this->logger()->reportTimedOutMutation($event->test); - } - }, - new class($printer) extends PrinterSubscriber implements UncoveredSubscriber { public function notify(Uncovered $event): void @@ -273,14 +249,6 @@ public function notify(Uncovered $event): void } }, - new class($this->logger) extends LoggerSubscriber implements UncoveredSubscriber - { - public function notify(Uncovered $event): void - { - $this->logger()->reportUncoveredMutation($event->test); - } - }, - // MutationSuite new class($printer) extends PrinterSubscriber implements StartMutationGenerationSubscriber { @@ -314,6 +282,39 @@ public function notify(FinishMutationSuite $event): void } }, + // Logging + new class($this->logger) extends LoggerSubscriber implements TestedSubscriber + { + public function notify(Tested $event): void + { + $this->logger()->reportTestedMutation($event->test); + } + }, + + new class($this->logger) extends LoggerSubscriber implements UntestedSubscriber + { + public function notify(Untested $event): void + { + $this->logger()->reportUntestedMutation($event->test); + } + }, + + new class($this->logger) extends LoggerSubscriber implements TimeoutSubscriber + { + public function notify(Timeout $event): void + { + $this->logger()->reportTimedOutMutation($event->test); + } + }, + + new class($this->logger) extends LoggerSubscriber implements UncoveredSubscriber + { + public function notify(Uncovered $event): void + { + $this->logger()->reportUncoveredMutation($event->test); + } + }, + new class($this->logger) extends LoggerSubscriber implements FinishMutationSuiteSubscriber { public function notify(FinishMutationSuite $event): void From 2c378863f8e8fe504a7dd9bf8e42b77760a1959e Mon Sep 17 00:00:00 2001 From: lasserafn Date: Mon, 9 Sep 2024 19:58:41 +0200 Subject: [PATCH 09/14] prep --- src/Contracts/Logger.php | 17 ++++++++++++----- src/Plugins/Mutate.php | 10 +++++----- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/Contracts/Logger.php b/src/Contracts/Logger.php index 3879f95..f28361d 100644 --- a/src/Contracts/Logger.php +++ b/src/Contracts/Logger.php @@ -4,6 +4,9 @@ namespace Pest\Mutate\Contracts; + use Pest\Mutate\MutationSuite; + use Pest\Mutate\MutationTest; + /** * @internal * @@ -17,11 +20,15 @@ interface Logger */ public function __construct( string $outputPath, array $pluginSettings ); - /** - * @param array $uncoveredLines - * @param array $uncoveredLinesIgnored - */ - public function append(string $path, array $uncoveredLines, array $uncoveredLinesIgnored, float $percentage):void; + public function pushTestedMutation( MutationTest $mutationTest ): void; + + public function pushUntestedMutation( MutationTest $mutationTest ): void; + + public function pushTimedOutMutation( MutationTest $mutationTest ): void; + + public function pushUncoveredMutation( MutationTest $mutationTest ): void; + + public function mutationSuiteFinished( MutationSuite $mutationSuite ): void; public function output():void; } diff --git a/src/Plugins/Mutate.php b/src/Plugins/Mutate.php index a5ff720..ac80155 100644 --- a/src/Plugins/Mutate.php +++ b/src/Plugins/Mutate.php @@ -287,7 +287,7 @@ public function notify(FinishMutationSuite $event): void { public function notify(Tested $event): void { - $this->logger()->reportTestedMutation($event->test); + $this->logger()->pushTestedMutation($event->test); } }, @@ -295,7 +295,7 @@ public function notify(Tested $event): void { public function notify(Untested $event): void { - $this->logger()->reportUntestedMutation($event->test); + $this->logger()->pushUntestedMutation($event->test); } }, @@ -303,7 +303,7 @@ public function notify(Untested $event): void { public function notify(Timeout $event): void { - $this->logger()->reportTimedOutMutation($event->test); + $this->logger()->pushTimedOutMutation($event->test); } }, @@ -311,7 +311,7 @@ public function notify(Timeout $event): void { public function notify(Uncovered $event): void { - $this->logger()->reportUncoveredMutation($event->test); + $this->logger()->pushUncoveredMutation($event->test); } }, @@ -319,7 +319,7 @@ public function notify(Uncovered $event): void { public function notify(FinishMutationSuite $event): void { - $this->logger()->reportMutationSuiteFinished($event->mutationSuite); + $this->logger()->mutationSuiteFinished($event->mutationSuite); } }, ]; From 9ca1c4569f0761af38f655f224e62105187be2db Mon Sep 17 00:00:00 2001 From: lasserafn Date: Mon, 9 Sep 2024 19:58:45 +0200 Subject: [PATCH 10/14] prep --- src/Contracts/Logger.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Contracts/Logger.php b/src/Contracts/Logger.php index f28361d..14cedbf 100644 --- a/src/Contracts/Logger.php +++ b/src/Contracts/Logger.php @@ -29,6 +29,4 @@ public function pushTimedOutMutation( MutationTest $mutationTest ): void; public function pushUncoveredMutation( MutationTest $mutationTest ): void; public function mutationSuiteFinished( MutationSuite $mutationSuite ): void; - - public function output():void; } From 54751c2e9a4a7a9285dcf62b23b9ab569d7d73c3 Mon Sep 17 00:00:00 2001 From: lasserafn Date: Wed, 11 Sep 2024 19:03:01 +0200 Subject: [PATCH 11/14] Prep --- src/Contracts/Logger.php | 12 +------ src/Logging/JsonLogger.php | 71 +++++++++++++++++++++++--------------- src/Logging/NullLogger.php | 12 ++----- src/Plugins/Mutate.php | 36 ++----------------- 4 files changed, 49 insertions(+), 82 deletions(-) diff --git a/src/Contracts/Logger.php b/src/Contracts/Logger.php index 14cedbf..6fa9839 100644 --- a/src/Contracts/Logger.php +++ b/src/Contracts/Logger.php @@ -5,7 +5,6 @@ namespace Pest\Mutate\Contracts; use Pest\Mutate\MutationSuite; - use Pest\Mutate\MutationTest; /** * @internal @@ -16,17 +15,8 @@ interface Logger { /** * @param string $outputPath - * @param array $pluginSettings */ - public function __construct( string $outputPath, array $pluginSettings ); - - public function pushTestedMutation( MutationTest $mutationTest ): void; - - public function pushUntestedMutation( MutationTest $mutationTest ): void; - - public function pushTimedOutMutation( MutationTest $mutationTest ): void; - - public function pushUncoveredMutation( MutationTest $mutationTest ): void; + public function __construct( string $outputPath ); public function mutationSuiteFinished( MutationSuite $mutationSuite ): void; } diff --git a/src/Logging/JsonLogger.php b/src/Logging/JsonLogger.php index 155996b..0fb9a29 100644 --- a/src/Logging/JsonLogger.php +++ b/src/Logging/JsonLogger.php @@ -5,6 +5,7 @@ namespace Pest\Mutate\Logging; use Pest\Mutate\Contracts\Logger; +use Pest\Mutate\MutationSuite; /** * @internal @@ -15,35 +16,49 @@ class JsonLogger implements Logger { private string $outputPath; - /** @var array */ - private array $pluginSettings; - - /** @var array>> */ - private array $logs = []; - - public function __construct( string $outputPath, array $pluginSettings ) { + public function __construct( string $outputPath ) { $this->outputPath = $outputPath; - $this->pluginSettings = $pluginSettings; } - public function append(string $path, array $uncoveredLines, array $uncoveredLinesIgnored, float $percentage):void - { - $this->logs[] = [ - 'file' => $path, - 'uncoveredLines' => $uncoveredLines, - 'uncoveredLinesIgnored' => $uncoveredLinesIgnored, - 'percentage' => $percentage, - ]; - } - - public function output(): void - { - $json = json_encode( [ - 'format' => 'pest', - 'settings' => $this->pluginSettings, - 'result' => $this->logs, - 'total' => round( array_sum(array_column($this->logs, 'percentage')) / count($this->logs), 2 ) - ], JSON_THROW_ON_ERROR ); - file_put_contents($this->outputPath, $json); - } + public function mutationSuiteFinished( MutationSuite $mutationSuite ): void { + $json = json_encode( [ + 'format' => 'pest', + 'results' => array_map(function($testCollection) { + return [ + 'path' => $testCollection->file->getRealPath(), + 'count_total' => $testCollection->count(), + 'count_not_run' => $testCollection->notRun(), + 'count_timed_out' => $testCollection->timedOut(), + 'count_uncovered' => $testCollection->uncovered(), + 'count_untested' => $testCollection->untested(), + 'tests' => array_map(function($test) { + return [ + 'id' => $test->getId(), + 'duration' => $test->duration(), + 'result' => $test->result()->value, + 'mutation' => [ + 'id' =>$test->mutation->id, + 'mutator' =>$test->mutation->mutator, + 'start_line' =>$test->mutation->startLine, + 'end_line' =>$test->mutation->endLine, + ], + ]; + }, $testCollection->tests()) + ]; + }, $mutationSuite->repository->all()), + 'stats' => [ + 'duration' => $mutationSuite->duration(), + 'score' => $mutationSuite->repository->score(), + 'tests' => [ + 'count_total' => $mutationSuite->repository->count(), + 'count_not_run' => $mutationSuite->repository->notRun(), + 'count_timed_out' => $mutationSuite->repository->timedOut(), + 'count_uncovered' => $mutationSuite->repository->uncovered(), + 'count_untested' => $mutationSuite->repository->untested(), + ], + ], + $mutationSuite->repository->notRun() + ], JSON_THROW_ON_ERROR ); + file_put_contents($this->outputPath, $json); + } } diff --git a/src/Logging/NullLogger.php b/src/Logging/NullLogger.php index 8841089..fddfcd6 100644 --- a/src/Logging/NullLogger.php +++ b/src/Logging/NullLogger.php @@ -5,6 +5,7 @@ namespace Pest\Mutate\Logging; use Pest\Mutate\Contracts\Logger; +use Pest\Mutate\MutationSuite; /** * @internal @@ -15,20 +16,13 @@ class NullLogger implements Logger { /** * @param string $outputPath - * @param array $pluginSettings */ - public function __construct( string $outputPath, array $pluginSettings ) + public function __construct( string $outputPath = '' ) { // } - public function append(string $path, array $uncoveredLines, array $uncoveredLinesIgnored, float $percentage):void - { - // - } - - public function output(): void - { + public function mutationSuiteFinished( MutationSuite $mutationSuite ): void { // } } diff --git a/src/Plugins/Mutate.php b/src/Plugins/Mutate.php index ac80155..befe149 100644 --- a/src/Plugins/Mutate.php +++ b/src/Plugins/Mutate.php @@ -84,7 +84,7 @@ public function __construct( private readonly Container $container, private readonly OutputInterface $output, ) { - $this->logger = new NullLogger('', []); + $this->logger = new NullLogger(); } public function boot(): void @@ -141,7 +141,7 @@ public function handleArguments(array $arguments): array } if ($this->hasArgument('--output-json', $arguments)) { - $this->logger = new JsonLogger(explode('=', array_flip($arguments)['--output-json'])[1], ['test' => true]); + $this->logger = new JsonLogger(explode('=', array_flip($arguments)['--output-json'])[1]); } $arguments = Container::getInstance()->get(ConfigurationRepository::class) // @phpstan-ignore-line @@ -283,38 +283,6 @@ public function notify(FinishMutationSuite $event): void }, // Logging - new class($this->logger) extends LoggerSubscriber implements TestedSubscriber - { - public function notify(Tested $event): void - { - $this->logger()->pushTestedMutation($event->test); - } - }, - - new class($this->logger) extends LoggerSubscriber implements UntestedSubscriber - { - public function notify(Untested $event): void - { - $this->logger()->pushUntestedMutation($event->test); - } - }, - - new class($this->logger) extends LoggerSubscriber implements TimeoutSubscriber - { - public function notify(Timeout $event): void - { - $this->logger()->pushTimedOutMutation($event->test); - } - }, - - new class($this->logger) extends LoggerSubscriber implements UncoveredSubscriber - { - public function notify(Uncovered $event): void - { - $this->logger()->pushUncoveredMutation($event->test); - } - }, - new class($this->logger) extends LoggerSubscriber implements FinishMutationSuiteSubscriber { public function notify(FinishMutationSuite $event): void From 3991087a6ea1592f8bcff3294a5bc3fcc48c6ff1 Mon Sep 17 00:00:00 2001 From: lasserafn Date: Mon, 30 Sep 2024 18:15:08 +0200 Subject: [PATCH 12/14] Mutation Coverage output --- src/Logging/JsonLogger.php | 69 ++++++++--------- src/Plugins/Mutate.php | 2 +- tests/Logging/JsonLoggerTest.php | 91 ++++++++++++++++++++++ tests/Logging/LoggingTest.php | 126 ------------------------------- 4 files changed, 127 insertions(+), 161 deletions(-) create mode 100644 tests/Logging/JsonLoggerTest.php delete mode 100644 tests/Logging/LoggingTest.php diff --git a/src/Logging/JsonLogger.php b/src/Logging/JsonLogger.php index 0fb9a29..b3b942c 100644 --- a/src/Logging/JsonLogger.php +++ b/src/Logging/JsonLogger.php @@ -8,57 +8,58 @@ use Pest\Mutate\MutationSuite; /** -* @internal -* -* @final -*/ + * @internal + * + * @final + */ class JsonLogger implements Logger { - private string $outputPath; + private string $outputPath; - public function __construct( string $outputPath ) { - $this->outputPath = $outputPath; - } + public function __construct( string $outputPath ) + { + $this->outputPath = $outputPath; + } - public function mutationSuiteFinished( MutationSuite $mutationSuite ): void { + public function mutationSuiteFinished( MutationSuite $mutationSuite ): void + { $json = json_encode( [ - 'format' => 'pest', - 'results' => array_map(function($testCollection) { + 'format' => 'pest', + 'results' => array_map( function ( $testCollection ) { return [ - 'path' => $testCollection->file->getRealPath(), - 'count_total' => $testCollection->count(), - 'count_not_run' => $testCollection->notRun(), + 'path' => $testCollection->file->getPath(), + 'count_total' => $testCollection->count(), + 'count_not_run' => $testCollection->notRun(), 'count_timed_out' => $testCollection->timedOut(), 'count_uncovered' => $testCollection->uncovered(), - 'count_untested' => $testCollection->untested(), - 'tests' => array_map(function($test) { + 'count_untested' => $testCollection->untested(), + 'tests' => array_map( function ( $test ) { return [ - 'id' => $test->getId(), + 'id' => $test->getId(), 'duration' => $test->duration(), - 'result' => $test->result()->value, + 'result' => $test->result()->value, 'mutation' => [ - 'id' =>$test->mutation->id, - 'mutator' =>$test->mutation->mutator, - 'start_line' =>$test->mutation->startLine, - 'end_line' =>$test->mutation->endLine, - ], + 'id' => $test->mutation->id, + 'mutator' => $test->mutation->mutator, + 'start_line' => $test->mutation->startLine, + 'end_line' => $test->mutation->endLine, + ], ]; - }, $testCollection->tests()) + }, $testCollection->tests() ) ]; - }, $mutationSuite->repository->all()), - 'stats' => [ - 'duration' => $mutationSuite->duration(), - 'score' => $mutationSuite->repository->score(), - 'tests' => [ - 'count_total' => $mutationSuite->repository->count(), - 'count_not_run' => $mutationSuite->repository->notRun(), + }, $mutationSuite->repository->all() ), + 'stats' => [ + 'duration' => round($mutationSuite->duration(), 3), + 'score' => $mutationSuite->repository->score(), + 'tests' => [ + 'count_total' => $mutationSuite->repository->count(), + 'count_not_run' => $mutationSuite->repository->notRun(), 'count_timed_out' => $mutationSuite->repository->timedOut(), 'count_uncovered' => $mutationSuite->repository->uncovered(), - 'count_untested' => $mutationSuite->repository->untested(), + 'count_untested' => $mutationSuite->repository->untested(), ], ], - $mutationSuite->repository->notRun() ], JSON_THROW_ON_ERROR ); - file_put_contents($this->outputPath, $json); + file_put_contents( $this->outputPath, $json ); } } diff --git a/src/Plugins/Mutate.php b/src/Plugins/Mutate.php index befe149..e31a929 100644 --- a/src/Plugins/Mutate.php +++ b/src/Plugins/Mutate.php @@ -140,7 +140,7 @@ public function handleArguments(array $arguments): array $arguments[] = '--coverage-php='.Coverage::getPath(); } - if ($this->hasArgument('--output-json', $arguments)) { + if ($this->hasArgument('--mutate-output-json', $arguments)) { $this->logger = new JsonLogger(explode('=', array_flip($arguments)['--output-json'])[1]); } diff --git a/tests/Logging/JsonLoggerTest.php b/tests/Logging/JsonLoggerTest.php new file mode 100644 index 0000000..71ebabe --- /dev/null +++ b/tests/Logging/JsonLoggerTest.php @@ -0,0 +1,91 @@ +repository->add( new Mutation( + id: 'test-id', + file: new SplFileInfo( 'test.php', '', '' ), + mutator: EqualToIdentical::class, + startLine: 4, + endLine: 4, + diff: <<<'DIFF' + --- Expected + +++ Actual + @@ @@ + + - return 1 == '1'; + + return 1 === '1'; + + DIFF, + modifiedSourcePath: 'test-modified.php', + ) ); + $suite->repository->all()[0]->tests()[0]->updateResult( MutationTestResult::Tested ); + $suite->trackStart(); + $suite->trackFinish(); + + $logger->mutationSuiteFinished( $suite ); + + expect( __DIR__ . '/mutation-output.json' )->toBeReadableFile(); + + expect( file_get_contents( __DIR__ . '/mutation-output.json' ) )->json()->toMatchArray( [ + 'format' => 'pest', + 'results' => + [ + [ + 'path' => false, + 'count_total' => 1, + 'count_not_run' => 0, + 'count_timed_out' => 0, + 'count_uncovered' => 0, + 'count_untested' => 0, + 'tests' => + [ + 0 => + [ + 'id' => 'test-id', + 'duration' => 0, + 'result' => 'tested', + 'mutation' => + [ + 'id' => 'test-id', + 'mutator' => 'Pest\\Mutate\\Mutators\\Equality\\EqualToIdentical', + 'start_line' => 4, + 'end_line' => 4, + ], + ], + ], + ], + ], + 'stats' => + [ + 'duration' => 0, + 'score' => 100, + 'tests' => + [ + 'count_total' => 1, + 'count_not_run' => 0, + 'count_timed_out' => 0, + 'count_uncovered' => 0, + 'count_untested' => 0, + ], + ], + ] ); +} ); diff --git a/tests/Logging/LoggingTest.php b/tests/Logging/LoggingTest.php deleted file mode 100644 index fb9819d..0000000 --- a/tests/Logging/LoggingTest.php +++ /dev/null @@ -1,126 +0,0 @@ - $plugin->handleArguments( [ '--type-coverage', '--type-coverage-json=test.json' ] ) )->toThrow( Exception::class, 0 ); - - expect( __DIR__ . '/../test.json' )->toBeReadableFile(); - expect( file_get_contents( __DIR__ . '/../test.json' ) )->json()->toMatchArray( [ - "format" => "pest", - 'settings' => [ - 'coverageMin' => 0, - ], - "result" => [ - [ - "file" => "src/PHPStanAnalyser.php", - "uncoveredLines" => [], - "uncoveredLinesIgnored" => [], - "percentage" => 100, - ], - [ - "file" => "src/TestCaseForTypeCoverage.php", - "uncoveredLines" => [], - "uncoveredLinesIgnored" => [], - "percentage" => 100, - ], - [ - "file" => "src/Contracts/Logger.php", - "uncoveredLines" => [], - "uncoveredLinesIgnored" => [], - "percentage" => 100, - ], - [ - "file" => "src/Plugin.php", - "uncoveredLines" => [], - "uncoveredLinesIgnored" => [], - "percentage" => 100, - ], - [ - "file" => "src/Result.php", - "uncoveredLines" => [], - "uncoveredLinesIgnored" => [], - "percentage" => 100, - ], - [ - "file" => "src/Error.php", - "uncoveredLines" => [], - "uncoveredLinesIgnored" => [], - "percentage" => 100, - ], - [ - "file" => "src/Support/ConfigurationSourceDetector.php", - "uncoveredLines" => [], - "uncoveredLinesIgnored" => [], - "percentage" => 100, - ], - [ - "file" => "src/Analyser.php", - "uncoveredLines" => [], - "uncoveredLinesIgnored" => [], - "percentage" => 100, - ], - [ - "file" => "src/Logging/NullLogger.php", - "uncoveredLines" => [], - "uncoveredLinesIgnored" => [], - "percentage" => 100, - ], - [ - "file" => "src/Logging/JsonLogger.php", - "uncoveredLines" => [], - "uncoveredLinesIgnored" => [], - "percentage" => 100, - ], - [ - "file" => "tests/Fixtures/Properties.php", - "uncoveredLines" => ["pr12"], - "uncoveredLinesIgnored" => [], - "percentage" => 83, - ], - [ - "file" => "tests/Fixtures/All.php", - "uncoveredLines" => ["pr12", "pa14", "pa14", "rt14"], - "uncoveredLinesIgnored" => [], - "percentage" => 0, - ], - [ - "file" => "tests/Fixtures/ReturnType.php", - "uncoveredLines" => ["rt12"], - "uncoveredLinesIgnored" => [], - "percentage" => 67, - ], - [ - "file" => "tests/Fixtures/Parameters.php", - "uncoveredLines" => ["pa12"], - "uncoveredLinesIgnored" => [], - "percentage" => 83, - ], - ], - 'total' => 88.07, - ]); -} ); From a43608debdc1840f77e7b6f904a0b24f733cb306 Mon Sep 17 00:00:00 2001 From: lasserafn Date: Mon, 30 Sep 2024 18:24:16 +0200 Subject: [PATCH 13/14] Mutation Coverage output --- src/Plugins/Mutate.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Plugins/Mutate.php b/src/Plugins/Mutate.php index e31a929..267d994 100644 --- a/src/Plugins/Mutate.php +++ b/src/Plugins/Mutate.php @@ -141,7 +141,7 @@ public function handleArguments(array $arguments): array } if ($this->hasArgument('--mutate-output-json', $arguments)) { - $this->logger = new JsonLogger(explode('=', array_flip($arguments)['--output-json'])[1]); + $this->logger = new JsonLogger(explode('=', array_flip($arguments)['--mutate-output-json'])[1]); } $arguments = Container::getInstance()->get(ConfigurationRepository::class) // @phpstan-ignore-line From c359bc185091dfa72b1e8c84dbe8871bb0766789 Mon Sep 17 00:00:00 2001 From: lasserafn Date: Mon, 30 Sep 2024 18:35:12 +0200 Subject: [PATCH 14/14] Fix --- src/Logging/JsonLogger.php | 10 +++++----- src/Plugins/Mutate.php | 13 ++++++++----- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/Logging/JsonLogger.php b/src/Logging/JsonLogger.php index b3b942c..fd7c12d 100644 --- a/src/Logging/JsonLogger.php +++ b/src/Logging/JsonLogger.php @@ -25,9 +25,9 @@ public function mutationSuiteFinished( MutationSuite $mutationSuite ): void { $json = json_encode( [ 'format' => 'pest', - 'results' => array_map( function ( $testCollection ) { + 'results' => array_values( array_map( function ( $testCollection ) { return [ - 'path' => $testCollection->file->getPath(), + 'path' => $testCollection->file->getRealPath(), 'count_total' => $testCollection->count(), 'count_not_run' => $testCollection->notRun(), 'count_timed_out' => $testCollection->timedOut(), @@ -36,7 +36,7 @@ public function mutationSuiteFinished( MutationSuite $mutationSuite ): void 'tests' => array_map( function ( $test ) { return [ 'id' => $test->getId(), - 'duration' => $test->duration(), + 'duration' => round( $test->duration(), 4 ), 'result' => $test->result()->value, 'mutation' => [ 'id' => $test->mutation->id, @@ -47,9 +47,9 @@ public function mutationSuiteFinished( MutationSuite $mutationSuite ): void ]; }, $testCollection->tests() ) ]; - }, $mutationSuite->repository->all() ), + }, $mutationSuite->repository->all() ) ), 'stats' => [ - 'duration' => round($mutationSuite->duration(), 3), + 'duration' => round( $mutationSuite->duration(), 4 ), 'score' => $mutationSuite->repository->score(), 'tests' => [ 'count_total' => $mutationSuite->repository->count(), diff --git a/src/Plugins/Mutate.php b/src/Plugins/Mutate.php index 267d994..90e1a1c 100644 --- a/src/Plugins/Mutate.php +++ b/src/Plugins/Mutate.php @@ -130,6 +130,13 @@ public function handleArguments(array $arguments): array throw new InvalidOption('Mutation testing requires code coverage to be enabled. You can find more about code coverage in the Pest documentation.'); } + foreach ($arguments as $argIndex => $arg) { + if (str_starts_with((string) $arg, "--mutate-output-json=")) { // @phpstan-ignore-linereturn true; + $this->logger = new JsonLogger(explode('=', $arg)[1]); + unset($arguments[$argIndex]); + } + } + $mutationTestRunner->enable(); $this->ensurePrinterIsRegistered(); @@ -140,12 +147,8 @@ public function handleArguments(array $arguments): array $arguments[] = '--coverage-php='.Coverage::getPath(); } - if ($this->hasArgument('--mutate-output-json', $arguments)) { - $this->logger = new JsonLogger(explode('=', array_flip($arguments)['--mutate-output-json'])[1]); - } - $arguments = Container::getInstance()->get(ConfigurationRepository::class) // @phpstan-ignore-line - ->cliConfiguration->fromArguments($arguments); + ->cliConfiguration->fromArguments($arguments); $mutationTestRunner->setOriginalArguments($arguments);