diff --git a/composer.json b/composer.json index c66f40706..b27459b20 100644 --- a/composer.json +++ b/composer.json @@ -47,7 +47,7 @@ "ext-json": "*", "ext-libxml": "*", "composer/xdebug-handler": "^2.0", - "infection/abstract-testframework-adapter": "^0.3.1", + "infection/abstract-testframework-adapter": "^0.5.0", "infection/extension-installer": "^0.1.0", "infection/include-interceptor": "^0.2.4", "justinrainbow/json-schema": "^5.2.10", diff --git a/composer.lock b/composer.lock index 89b035c5a..5fce70f41 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "e386c963bbc78549523114db79bcb94c", + "content-hash": "d9cfb23acce60abd6aa6cc78193cd142", "packages": [ { "name": "composer/xdebug-handler", @@ -72,25 +72,25 @@ }, { "name": "infection/abstract-testframework-adapter", - "version": "0.3.1", + "version": "0.5.0", "source": { "type": "git", "url": "https://github.com/infection/abstract-testframework-adapter.git", - "reference": "c52539339f28d6b67625ff24496289b3e6d66025" + "reference": "18925e20d15d1a5995bb85c9dc09e8751e1e069b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/infection/abstract-testframework-adapter/zipball/c52539339f28d6b67625ff24496289b3e6d66025", - "reference": "c52539339f28d6b67625ff24496289b3e6d66025", + "url": "https://api.github.com/repos/infection/abstract-testframework-adapter/zipball/18925e20d15d1a5995bb85c9dc09e8751e1e069b", + "reference": "18925e20d15d1a5995bb85c9dc09e8751e1e069b", "shasum": "" }, "require": { - "php": "^7.3 || ^8.0" + "php": "^7.4 || ^8.0" }, "require-dev": { "ergebnis/composer-normalize": "^2.8", - "friendsofphp/php-cs-fixer": "^2.16", - "phpunit/phpunit": "^9.0" + "friendsofphp/php-cs-fixer": "^2.17", + "phpunit/phpunit": "^9.5" }, "type": "library", "autoload": { @@ -111,9 +111,19 @@ "description": "Abstract Test Framework Adapter for Infection", "support": { "issues": "https://github.com/infection/abstract-testframework-adapter/issues", - "source": "https://github.com/infection/abstract-testframework-adapter/tree/0.3" + "source": "https://github.com/infection/abstract-testframework-adapter/tree/0.5.0" }, - "time": "2020-08-30T13:50:12+00:00" + "funding": [ + { + "url": "https://github.com/infection", + "type": "github" + }, + { + "url": "https://opencollective.com/infection", + "type": "open_collective" + } + ], + "time": "2021-08-17T18:49:12+00:00" }, { "name": "infection/extension-installer", diff --git a/resources/schema.json b/resources/schema.json index a274eebe3..a17f81b67 100644 --- a/resources/schema.json +++ b/resources/schema.json @@ -339,6 +339,7 @@ "SpreadOneItem": { "$ref": "#/definitions/default-mutator-config" }, "SpreadAssignment": { "$ref": "#/definitions/default-mutator-config" }, "SpreadRemoval": { "$ref": "#/definitions/default-mutator-config" }, + "SyntaxError": { "$ref": "#/definitions/default-mutator-config" }, "Foreach_": { "$ref": "#/definitions/default-mutator-config" }, "For_": { "$ref": "#/definitions/default-mutator-config" }, "DoWhile": { "$ref": "#/definitions/default-mutator-config" }, diff --git a/src/Console/OutputFormatter/DotFormatter.php b/src/Console/OutputFormatter/DotFormatter.php index 87920f9a1..204964c35 100644 --- a/src/Console/OutputFormatter/DotFormatter.php +++ b/src/Console/OutputFormatter/DotFormatter.php @@ -66,6 +66,7 @@ public function start(int $mutationCount): void . 'M: escaped, ' . 'U: uncovered, ' . 'E: fatal error, ' + . 'X: syntax error, ' . 'T: timed out, ' . 'S: skipped', '', @@ -100,6 +101,10 @@ public function advance(MutantExecutionResult $executionResult, int $mutationCou case DetectionStatus::ERROR: $this->output->write('E'); + break; + case DetectionStatus::SYNTAX_ERROR: + $this->output->write('X'); + break; } diff --git a/src/Console/OutputFormatterStyleConfigurator.php b/src/Console/OutputFormatterStyleConfigurator.php index 55e62eb63..66e3bccbc 100644 --- a/src/Console/OutputFormatterStyleConfigurator.php +++ b/src/Console/OutputFormatterStyleConfigurator.php @@ -59,6 +59,7 @@ public static function configure(OutputInterface $output): void private static function configureMutantStyle(OutputFormatterInterface $formatter): void { $formatter->setStyle('with-error', new OutputFormatterStyle('green')); + $formatter->setStyle('with-syntax-error', new OutputFormatterStyle('red', null, ['bold'])); $formatter->setStyle( 'uncovered', new OutputFormatterStyle('blue', null, ['bold']) diff --git a/src/Event/Subscriber/MutationTestingConsoleLoggerSubscriber.php b/src/Event/Subscriber/MutationTestingConsoleLoggerSubscriber.php index 7fb1eb3dc..f18146864 100644 --- a/src/Event/Subscriber/MutationTestingConsoleLoggerSubscriber.php +++ b/src/Event/Subscriber/MutationTestingConsoleLoggerSubscriber.php @@ -150,6 +150,7 @@ private function showMetrics(): void $this->output->writeln('' . $this->getPadded($this->metricsCalculator->getNotTestedCount()) . ' mutants were not covered by tests'); $this->output->writeln('' . $this->getPadded($this->metricsCalculator->getEscapedCount()) . ' covered mutants were not detected'); $this->output->writeln('' . $this->getPadded($this->metricsCalculator->getErrorCount()) . ' errors were encountered'); + $this->output->writeln('' . $this->getPadded($this->metricsCalculator->getSyntaxErrorCount()) . ' syntax errors were encountered'); $this->output->writeln('' . $this->getPadded($this->metricsCalculator->getTimedOutCount()) . ' time outs were encountered'); $this->output->writeln('' . $this->getPadded($this->metricsCalculator->getSkippedCount()) . ' mutants required more time than configured'); diff --git a/src/Logger/DebugFileLogger.php b/src/Logger/DebugFileLogger.php index ea7f7b3bb..9e6bbc3b0 100644 --- a/src/Logger/DebugFileLogger.php +++ b/src/Logger/DebugFileLogger.php @@ -84,6 +84,11 @@ public function getLogLines(): array 'Errors', $separateSections ); + $logs[] = $this->getResultsLine( + $this->resultsCollector->getSyntaxErrorExecutionResults(), + 'Syntax Errors', + $separateSections + ); $logs[] = $this->getResultsLine( $this->resultsCollector->getEscapedExecutionResults(), 'Escaped', diff --git a/src/Logger/FederatedLogger.php b/src/Logger/FederatedLogger.php index 3d90363e1..fe369abb4 100644 --- a/src/Logger/FederatedLogger.php +++ b/src/Logger/FederatedLogger.php @@ -43,7 +43,7 @@ final class FederatedLogger implements MutationTestingResultsLogger /** * @var MutationTestingResultsLogger[] */ - private $loggers; + private array $loggers; public function __construct(MutationTestingResultsLogger ...$loggers) { diff --git a/src/Logger/JsonLogger.php b/src/Logger/JsonLogger.php index 8f9849efd..de363cbd1 100644 --- a/src/Logger/JsonLogger.php +++ b/src/Logger/JsonLogger.php @@ -74,6 +74,7 @@ public function getLogLines(): array 'notCoveredCount' => $this->metricsCalculator->getNotTestedCount(), 'escapedCount' => $this->metricsCalculator->getEscapedCount(), 'errorCount' => $this->metricsCalculator->getErrorCount(), + 'syntaxErrorCount' => $this->metricsCalculator->getSyntaxErrorCount(), 'skippedCount' => $this->metricsCalculator->getSkippedCount(), 'timeOutCount' => $this->metricsCalculator->getTimedOutCount(), 'msi' => $this->metricsCalculator->getMutationScoreIndicator(), @@ -84,6 +85,7 @@ public function getLogLines(): array 'timeouted' => $this->getResultsLine($this->resultsCollector->getTimedOutExecutionResults()), 'killed' => $this->getResultsLine($this->resultsCollector->getKilledExecutionResults()), 'errored' => $this->getResultsLine($this->resultsCollector->getErrorExecutionResults()), + 'syntaxErrors' => $this->getResultsLine($this->resultsCollector->getSyntaxErrorExecutionResults()), 'uncovered' => $this->onlyCoveredMode ? [] : $this->getResultsLine($this->resultsCollector->getNotCoveredExecutionResults()), ]; diff --git a/src/Logger/PerMutatorLogger.php b/src/Logger/PerMutatorLogger.php index d9cf6c9ee..a6f2bda17 100644 --- a/src/Logger/PerMutatorLogger.php +++ b/src/Logger/PerMutatorLogger.php @@ -73,7 +73,7 @@ public function getLogLines(): array $calculatorPerMutator = $this->createMetricsPerMutators(); $table = [ - ['Mutator', 'Mutations', 'Killed', 'Escaped', 'Errors', 'Timed Out', 'Skipped', 'MSI (%s)', 'Covered MSI (%s)'], + ['Mutator', 'Mutations', 'Killed', 'Escaped', 'Errors', 'Syntax Errors', 'Timed Out', 'Skipped', 'MSI (%s)', 'Covered MSI (%s)'], ]; foreach ($calculatorPerMutator as $mutatorName => $calculator) { @@ -85,6 +85,7 @@ public function getLogLines(): array (string) $calculator->getKilledCount(), (string) $calculator->getEscapedCount(), (string) $calculator->getErrorCount(), + (string) $calculator->getSyntaxErrorCount(), (string) $calculator->getTimedOutCount(), (string) $calculator->getSkippedCount(), self::formatScore($calculator->getMutationScoreIndicator()), diff --git a/src/Logger/SummaryFileLogger.php b/src/Logger/SummaryFileLogger.php index 0e3480c14..e9044b756 100644 --- a/src/Logger/SummaryFileLogger.php +++ b/src/Logger/SummaryFileLogger.php @@ -59,6 +59,7 @@ public function getLogLines(): array '', 'Killed: ' . $this->metricsCalculator->getKilledCount(), 'Errored: ' . $this->metricsCalculator->getErrorCount(), + 'Syntax Errors: ' . $this->metricsCalculator->getSyntaxErrorCount(), 'Escaped: ' . $this->metricsCalculator->getEscapedCount(), 'Timed Out: ' . $this->metricsCalculator->getTimedOutCount(), 'Skipped: ' . $this->metricsCalculator->getSkippedCount(), diff --git a/src/Logger/TextFileLogger.php b/src/Logger/TextFileLogger.php index 1de18b03e..2c1630311 100644 --- a/src/Logger/TextFileLogger.php +++ b/src/Logger/TextFileLogger.php @@ -102,6 +102,12 @@ public function getLogLines(): array 'Errors', $separateSections ); + + $logs[] = $this->getResultsLine( + $this->resultsCollector->getSyntaxErrorExecutionResults(), + 'Syntax Errors', + $separateSections + ); } if (!$this->onlyCoveredMode) { diff --git a/src/Metrics/MetricsCalculator.php b/src/Metrics/MetricsCalculator.php index 859c5faf9..527c99092 100644 --- a/src/Metrics/MetricsCalculator.php +++ b/src/Metrics/MetricsCalculator.php @@ -103,6 +103,11 @@ public function getErrorCount(): int return $this->countByStatus[DetectionStatus::ERROR]; } + public function getSyntaxErrorCount(): int + { + return $this->countByStatus[DetectionStatus::SYNTAX_ERROR]; + } + public function getSkippedCount(): int { return $this->countByStatus[DetectionStatus::SKIPPED]; diff --git a/src/Metrics/ResultsCollector.php b/src/Metrics/ResultsCollector.php index e27da417f..7078c560c 100644 --- a/src/Metrics/ResultsCollector.php +++ b/src/Metrics/ResultsCollector.php @@ -105,6 +105,14 @@ public function getErrorExecutionResults(): array return $this->getResultListForStatus(DetectionStatus::ERROR)->getSortedExecutionResults(); } + /** + * @return MutantExecutionResult[] + */ + public function getSyntaxErrorExecutionResults(): array + { + return $this->getResultListForStatus(DetectionStatus::SYNTAX_ERROR)->getSortedExecutionResults(); + } + /** * @return MutantExecutionResult[] */ diff --git a/src/Metrics/TargetDetectionStatusesProvider.php b/src/Metrics/TargetDetectionStatusesProvider.php index be141bc8d..6915bc2b9 100644 --- a/src/Metrics/TargetDetectionStatusesProvider.php +++ b/src/Metrics/TargetDetectionStatusesProvider.php @@ -123,6 +123,8 @@ private function findRequired(): Generator yield DetectionStatus::ERROR; + yield DetectionStatus::SYNTAX_ERROR; + yield DetectionStatus::TIMED_OUT; if (!$this->onlyCoveredMode) { @@ -138,6 +140,8 @@ private function findRequired(): Generator yield DetectionStatus::SKIPPED; + yield DetectionStatus::SYNTAX_ERROR; + if ($this->logVerbosity === LogVerbosity::DEBUG) { yield DetectionStatus::KILLED; diff --git a/src/Mutant/DetectionStatus.php b/src/Mutant/DetectionStatus.php index 9b8fa1263..b3fcc4879 100644 --- a/src/Mutant/DetectionStatus.php +++ b/src/Mutant/DetectionStatus.php @@ -49,6 +49,7 @@ final class DetectionStatus public const ERROR = 'error'; public const TIMED_OUT = 'timed out'; public const SKIPPED = 'skipped'; + public const SYNTAX_ERROR = 'syntax error'; public const NOT_COVERED = 'not covered'; public const ALL = [ @@ -57,6 +58,7 @@ final class DetectionStatus self::ERROR, self::TIMED_OUT, self::SKIPPED, + self::SYNTAX_ERROR, self::NOT_COVERED, ]; } diff --git a/src/Mutant/MutantExecutionResultFactory.php b/src/Mutant/MutantExecutionResultFactory.php index cd487c511..c17731dd5 100644 --- a/src/Mutant/MutantExecutionResultFactory.php +++ b/src/Mutant/MutantExecutionResultFactory.php @@ -35,6 +35,7 @@ namespace Infection\Mutant; +use Infection\AbstractTestFramework\SyntaxErrorAware; use Infection\AbstractTestFramework\TestFrameworkAdapter; use Infection\Process\MutantProcess; use function Safe\sprintf; @@ -103,10 +104,16 @@ private function retrieveDetectionStatus(MutantProcess $mutantProcess): string return DetectionStatus::ERROR; } - if ($this->testFrameworkAdapter->testsPass($this->retrieveProcessOutput($process))) { + $output = $this->retrieveProcessOutput($process); + + if ($this->testFrameworkAdapter->testsPass($output)) { return DetectionStatus::ESCAPED; } + if ($this->testFrameworkAdapter instanceof SyntaxErrorAware && $this->testFrameworkAdapter->isSyntaxError($output)) { + return DetectionStatus::SYNTAX_ERROR; + } + return DetectionStatus::KILLED; } } diff --git a/src/Mutator/ProfileList.php b/src/Mutator/ProfileList.php index cb224528c..17bdf5407 100644 --- a/src/Mutator/ProfileList.php +++ b/src/Mutator/ProfileList.php @@ -464,6 +464,9 @@ final class ProfileList // Extensions 'BCMath' => Mutator\Extensions\BCMath::class, 'MBString' => Mutator\Extensions\MBString::class, + + // Internal only usage + 'SyntaxError' => Mutator\SyntaxError::class, ]; /** @var array|null */ diff --git a/src/Mutator/SyntaxError.php b/src/Mutator/SyntaxError.php new file mode 100644 index 000000000..1094b0150 --- /dev/null +++ b/src/Mutator/SyntaxError.php @@ -0,0 +1,81 @@ + + */ +final class SyntaxError implements Mutator +{ + use GetMutatorName; + + public static function getDefinition(): ?Definition + { + return new Definition( + 'Replaces a `$this` with `false` to produce a syntax error. Internal usage only.', + MutatorCategory::ORTHOGONAL_REPLACEMENT, + null, + <<<'DIFF' +class X { + function foo() + { +- $this->method(); ++ $->method(); + } +} +DIFF + ); + } + + /** + * @psalm-mutation-free + * + * @return iterable + */ + public function mutate(Node $node): iterable + { + yield new Node\Expr\ConstFetch(new Node\Name('$')); + } + + public function canMutate(Node $node): bool + { + return $node instanceof Node\Expr\Variable && $node->name === 'this'; + } +} diff --git a/src/TestFramework/PhpUnit/Adapter/PestAdapter.php b/src/TestFramework/PhpUnit/Adapter/PestAdapter.php index 3fb1dc642..fb829034e 100644 --- a/src/TestFramework/PhpUnit/Adapter/PestAdapter.php +++ b/src/TestFramework/PhpUnit/Adapter/PestAdapter.php @@ -36,6 +36,7 @@ namespace Infection\TestFramework\PhpUnit\Adapter; use Infection\AbstractTestFramework\MemoryUsageAware; +use Infection\AbstractTestFramework\SyntaxErrorAware; use Infection\AbstractTestFramework\TestFrameworkAdapter; use Infection\TestFramework\ProvidesInitialRunOnlyOptions; use function Safe\preg_match; @@ -44,7 +45,7 @@ /** * @internal */ -final class PestAdapter implements MemoryUsageAware, ProvidesInitialRunOnlyOptions, TestFrameworkAdapter +final class PestAdapter implements MemoryUsageAware, ProvidesInitialRunOnlyOptions, SyntaxErrorAware, TestFrameworkAdapter { private const NAME = 'Pest'; @@ -76,6 +77,11 @@ public function testsPass(string $output): bool return $isOk || $isOkRisked; } + public function isSyntaxError(string $output): bool + { + return preg_match('/ParseError\s*syntax error/i', $output) === 1; + } + public function hasJUnitReport(): bool { return $this->phpUnitAdapter->hasJUnitReport(); diff --git a/src/TestFramework/PhpUnit/Adapter/PhpUnitAdapter.php b/src/TestFramework/PhpUnit/Adapter/PhpUnitAdapter.php index 5258633b1..3b3b3e0c6 100644 --- a/src/TestFramework/PhpUnit/Adapter/PhpUnitAdapter.php +++ b/src/TestFramework/PhpUnit/Adapter/PhpUnitAdapter.php @@ -37,6 +37,7 @@ use function escapeshellarg; use Infection\AbstractTestFramework\MemoryUsageAware; +use Infection\AbstractTestFramework\SyntaxErrorAware; use Infection\Config\ValueProvider\PCOVDirectoryProvider; use Infection\TestFramework\AbstractTestFrameworkAdapter; use Infection\TestFramework\CommandLineArgumentsAndOptionsBuilder; @@ -54,7 +55,7 @@ * @internal * @final */ -class PhpUnitAdapter extends AbstractTestFrameworkAdapter implements MemoryUsageAware, ProvidesInitialRunOnlyOptions +class PhpUnitAdapter extends AbstractTestFrameworkAdapter implements MemoryUsageAware, ProvidesInitialRunOnlyOptions, SyntaxErrorAware { public const COVERAGE_DIR = 'coverage-xml'; @@ -142,6 +143,11 @@ public function testsPass(string $output): bool return $isOk || $isOkWithInfo || $isWarning | $isNoTestsExecuted; } + public function isSyntaxError(string $output): bool + { + return preg_match('/ParseError: syntax error/i', $output) === 1; + } + public function getMemoryUsed(string $output): float { if (preg_match('/Memory: (\d+(?:\.\d+))\s*MB/', $output, $match)) { diff --git a/tests/e2e/Config_Bootstrap/expected-output.txt b/tests/e2e/Config_Bootstrap/expected-output.txt index 7bcb80de3..a31fc060f 100644 --- a/tests/e2e/Config_Bootstrap/expected-output.txt +++ b/tests/e2e/Config_Bootstrap/expected-output.txt @@ -2,6 +2,7 @@ Total: 1 Killed: 1 Errored: 0 +Syntax Errors: 0 Escaped: 0 Timed Out: 0 Skipped: 0 diff --git a/tests/e2e/Custom_tmp_dir/expected-output.txt b/tests/e2e/Custom_tmp_dir/expected-output.txt index 7bcb80de3..a31fc060f 100644 --- a/tests/e2e/Custom_tmp_dir/expected-output.txt +++ b/tests/e2e/Custom_tmp_dir/expected-output.txt @@ -2,6 +2,7 @@ Total: 1 Killed: 1 Errored: 0 +Syntax Errors: 0 Escaped: 0 Timed Out: 0 Skipped: 0 diff --git a/tests/e2e/Empty_Path/expected-output.txt b/tests/e2e/Empty_Path/expected-output.txt index 7bcb80de3..a31fc060f 100644 --- a/tests/e2e/Empty_Path/expected-output.txt +++ b/tests/e2e/Empty_Path/expected-output.txt @@ -2,6 +2,7 @@ Total: 1 Killed: 1 Errored: 0 +Syntax Errors: 0 Escaped: 0 Timed Out: 0 Skipped: 0 diff --git a/tests/e2e/Example_Test/expected-output.txt b/tests/e2e/Example_Test/expected-output.txt index 7bcb80de3..a31fc060f 100644 --- a/tests/e2e/Example_Test/expected-output.txt +++ b/tests/e2e/Example_Test/expected-output.txt @@ -2,6 +2,7 @@ Total: 1 Killed: 1 Errored: 0 +Syntax Errors: 0 Escaped: 0 Timed Out: 0 Skipped: 0 diff --git a/tests/e2e/Example_Test/infection.json b/tests/e2e/Example_Test/infection.json index 7029746fb..a5d873d67 100644 --- a/tests/e2e/Example_Test/infection.json +++ b/tests/e2e/Example_Test/infection.json @@ -1,4 +1,5 @@ { + "$schema": "../../../resources/schema.json", "timeout": 25, "source": { "directories": [ diff --git a/tests/e2e/Exclude_Mutations_By_Regex/expected-output.txt b/tests/e2e/Exclude_Mutations_By_Regex/expected-output.txt index aa6c03830..95e73f9ca 100644 --- a/tests/e2e/Exclude_Mutations_By_Regex/expected-output.txt +++ b/tests/e2e/Exclude_Mutations_By_Regex/expected-output.txt @@ -2,6 +2,7 @@ Total: 0 Killed: 0 Errored: 0 +Syntax Errors: 0 Escaped: 0 Timed Out: 0 Skipped: 0 diff --git a/tests/e2e/Exclude_by_file_name/expected-output.txt b/tests/e2e/Exclude_by_file_name/expected-output.txt index 7bcb80de3..a31fc060f 100644 --- a/tests/e2e/Exclude_by_file_name/expected-output.txt +++ b/tests/e2e/Exclude_by_file_name/expected-output.txt @@ -2,6 +2,7 @@ Total: 1 Killed: 1 Errored: 0 +Syntax Errors: 0 Escaped: 0 Timed Out: 0 Skipped: 0 diff --git a/tests/e2e/Exec_Path/expected-output.txt b/tests/e2e/Exec_Path/expected-output.txt index afaccc04a..c654acc50 100644 --- a/tests/e2e/Exec_Path/expected-output.txt +++ b/tests/e2e/Exec_Path/expected-output.txt @@ -2,6 +2,7 @@ Total: 6 Killed: 5 Errored: 0 +Syntax Errors: 0 Escaped: 0 Timed Out: 0 Skipped: 0 diff --git a/tests/e2e/Ignore_All_Mutations/expected-output.txt b/tests/e2e/Ignore_All_Mutations/expected-output.txt index 76a558afd..b53522bf8 100644 --- a/tests/e2e/Ignore_All_Mutations/expected-output.txt +++ b/tests/e2e/Ignore_All_Mutations/expected-output.txt @@ -2,6 +2,7 @@ Total: 2 Killed: 2 Errored: 0 +Syntax Errors: 0 Escaped: 0 Timed Out: 0 Skipped: 0 diff --git a/tests/e2e/Ignore_MSI_Zero_Mutations/expected-output.txt b/tests/e2e/Ignore_MSI_Zero_Mutations/expected-output.txt index aa6c03830..95e73f9ca 100644 --- a/tests/e2e/Ignore_MSI_Zero_Mutations/expected-output.txt +++ b/tests/e2e/Ignore_MSI_Zero_Mutations/expected-output.txt @@ -2,6 +2,7 @@ Total: 0 Killed: 0 Errored: 0 +Syntax Errors: 0 Escaped: 0 Timed Out: 0 Skipped: 0 diff --git a/tests/e2e/Memory_Limit/expected-output.txt b/tests/e2e/Memory_Limit/expected-output.txt index 5aec86877..003c4078e 100644 --- a/tests/e2e/Memory_Limit/expected-output.txt +++ b/tests/e2e/Memory_Limit/expected-output.txt @@ -2,6 +2,7 @@ Total: 1 Killed: 0 Errored: 1 +Syntax Errors: 0 Escaped: 0 Timed Out: 0 Skipped: 0 diff --git a/tests/e2e/Multiline_Statement/expected-output.txt b/tests/e2e/Multiline_Statement/expected-output.txt index af47cacd2..b975cd448 100644 --- a/tests/e2e/Multiline_Statement/expected-output.txt +++ b/tests/e2e/Multiline_Statement/expected-output.txt @@ -49,6 +49,9 @@ Line 22 Errors mutants: =============== +Syntax Errors mutants: +====================== + Escaped mutants: ================ diff --git a/tests/e2e/Output_Stream/expected-output.txt b/tests/e2e/Output_Stream/expected-output.txt index 4cc565248..e887c84cd 100644 --- a/tests/e2e/Output_Stream/expected-output.txt +++ b/tests/e2e/Output_Stream/expected-output.txt @@ -13,6 +13,9 @@ Line 9 Errors mutants: =============== +Syntax Errors mutants: +====================== + Escaped mutants: ================ diff --git a/tests/e2e/PCOV_Directory/expected-output.txt b/tests/e2e/PCOV_Directory/expected-output.txt index 7bcb80de3..a31fc060f 100644 --- a/tests/e2e/PCOV_Directory/expected-output.txt +++ b/tests/e2e/PCOV_Directory/expected-output.txt @@ -2,6 +2,7 @@ Total: 1 Killed: 1 Errored: 0 +Syntax Errors: 0 Escaped: 0 Timed Out: 0 Skipped: 0 diff --git a/tests/e2e/PCOV_PHPUnit8/expected-output.txt b/tests/e2e/PCOV_PHPUnit8/expected-output.txt index 7bcb80de3..a31fc060f 100644 --- a/tests/e2e/PCOV_PHPUnit8/expected-output.txt +++ b/tests/e2e/PCOV_PHPUnit8/expected-output.txt @@ -2,6 +2,7 @@ Total: 1 Killed: 1 Errored: 0 +Syntax Errors: 0 Escaped: 0 Timed Out: 0 Skipped: 0 diff --git a/tests/e2e/PHPUnit93/expected-output.txt b/tests/e2e/PHPUnit93/expected-output.txt index 7bcb80de3..a31fc060f 100644 --- a/tests/e2e/PHPUnit93/expected-output.txt +++ b/tests/e2e/PHPUnit93/expected-output.txt @@ -2,6 +2,7 @@ Total: 1 Killed: 1 Errored: 0 +Syntax Errors: 0 Escaped: 0 Timed Out: 0 Skipped: 0 diff --git a/tests/e2e/PHPUnit_Custom_Config_Dir/expected-output.txt b/tests/e2e/PHPUnit_Custom_Config_Dir/expected-output.txt index 7bcb80de3..a31fc060f 100644 --- a/tests/e2e/PHPUnit_Custom_Config_Dir/expected-output.txt +++ b/tests/e2e/PHPUnit_Custom_Config_Dir/expected-output.txt @@ -2,6 +2,7 @@ Total: 1 Killed: 1 Errored: 0 +Syntax Errors: 0 Escaped: 0 Timed Out: 0 Skipped: 0 diff --git a/tests/e2e/PHPUnit_Hidden_Dependency/expected-output.txt b/tests/e2e/PHPUnit_Hidden_Dependency/expected-output.txt index 7bcb80de3..a31fc060f 100644 --- a/tests/e2e/PHPUnit_Hidden_Dependency/expected-output.txt +++ b/tests/e2e/PHPUnit_Hidden_Dependency/expected-output.txt @@ -2,6 +2,7 @@ Total: 1 Killed: 1 Errored: 0 +Syntax Errors: 0 Escaped: 0 Timed Out: 0 Skipped: 0 diff --git a/tests/e2e/PHPUnit_XSD_Validation/expected-output.txt b/tests/e2e/PHPUnit_XSD_Validation/expected-output.txt index 7bcb80de3..a31fc060f 100644 --- a/tests/e2e/PHPUnit_XSD_Validation/expected-output.txt +++ b/tests/e2e/PHPUnit_XSD_Validation/expected-output.txt @@ -2,6 +2,7 @@ Total: 1 Killed: 1 Errored: 0 +Syntax Errors: 0 Escaped: 0 Timed Out: 0 Skipped: 0 diff --git a/tests/e2e/PSR_0_Autoloader/expected-output.txt b/tests/e2e/PSR_0_Autoloader/expected-output.txt index 7bcb80de3..a31fc060f 100644 --- a/tests/e2e/PSR_0_Autoloader/expected-output.txt +++ b/tests/e2e/PSR_0_Autoloader/expected-output.txt @@ -2,6 +2,7 @@ Total: 1 Killed: 1 Errored: 0 +Syntax Errors: 0 Escaped: 0 Timed Out: 0 Skipped: 0 diff --git a/tests/e2e/PestTestFramework/expected-output.txt b/tests/e2e/PestTestFramework/expected-output.txt index 0a408ead3..00e5e6f54 100644 --- a/tests/e2e/PestTestFramework/expected-output.txt +++ b/tests/e2e/PestTestFramework/expected-output.txt @@ -2,6 +2,7 @@ Total: 11 Killed: 9 Errored: 0 +Syntax Errors: 0 Escaped: 2 Timed Out: 0 Skipped: 0 diff --git a/tests/e2e/PhpUnit_Depends_Order/expected-output.txt b/tests/e2e/PhpUnit_Depends_Order/expected-output.txt index aa6c03830..95e73f9ca 100644 --- a/tests/e2e/PhpUnit_Depends_Order/expected-output.txt +++ b/tests/e2e/PhpUnit_Depends_Order/expected-output.txt @@ -2,6 +2,7 @@ Total: 0 Killed: 0 Errored: 0 +Syntax Errors: 0 Escaped: 0 Timed Out: 0 Skipped: 0 diff --git a/tests/e2e/Phpunit_Bat_Wrapper/expected-output.txt b/tests/e2e/Phpunit_Bat_Wrapper/expected-output.txt index 7bcb80de3..a31fc060f 100644 --- a/tests/e2e/Phpunit_Bat_Wrapper/expected-output.txt +++ b/tests/e2e/Phpunit_Bat_Wrapper/expected-output.txt @@ -2,6 +2,7 @@ Total: 1 Killed: 1 Errored: 0 +Syntax Errors: 0 Escaped: 0 Timed Out: 0 Skipped: 0 diff --git a/tests/e2e/Profiles_Ignore_Combination/expected-output.txt b/tests/e2e/Profiles_Ignore_Combination/expected-output.txt index 01d3ef456..c0e51b061 100644 --- a/tests/e2e/Profiles_Ignore_Combination/expected-output.txt +++ b/tests/e2e/Profiles_Ignore_Combination/expected-output.txt @@ -2,6 +2,7 @@ Total: 4 Killed: 0 Errored: 0 +Syntax Errors: 0 Escaped: 0 Timed Out: 0 Skipped: 0 diff --git a/tests/e2e/Provide_Existing_Coverage/expected-output_phpunit.txt b/tests/e2e/Provide_Existing_Coverage/expected-output_phpunit.txt index e0322f347..e2f0f5d54 100644 --- a/tests/e2e/Provide_Existing_Coverage/expected-output_phpunit.txt +++ b/tests/e2e/Provide_Existing_Coverage/expected-output_phpunit.txt @@ -28,6 +28,9 @@ Line 15 Errors mutants: =============== +Syntax Errors mutants: +====================== + Escaped mutants: ================ diff --git a/tests/e2e/Save_PHPUnit_Bootstrap_File/expected-output.txt b/tests/e2e/Save_PHPUnit_Bootstrap_File/expected-output.txt index 7bcb80de3..a31fc060f 100644 --- a/tests/e2e/Save_PHPUnit_Bootstrap_File/expected-output.txt +++ b/tests/e2e/Save_PHPUnit_Bootstrap_File/expected-output.txt @@ -2,6 +2,7 @@ Total: 1 Killed: 1 Errored: 0 +Syntax Errors: 0 Escaped: 0 Timed Out: 0 Skipped: 0 diff --git a/tests/e2e/Skip_Initial_Tests/expected-output_phpunit.txt b/tests/e2e/Skip_Initial_Tests/expected-output_phpunit.txt index c73cd3f1f..9323b3835 100644 --- a/tests/e2e/Skip_Initial_Tests/expected-output_phpunit.txt +++ b/tests/e2e/Skip_Initial_Tests/expected-output_phpunit.txt @@ -28,6 +28,9 @@ Line 15 Errors mutants: =============== +Syntax Errors mutants: +====================== + Escaped mutants: ================ diff --git a/tests/e2e/Source_Directories_Config/expected-output.txt b/tests/e2e/Source_Directories_Config/expected-output.txt index 7bcb80de3..a31fc060f 100644 --- a/tests/e2e/Source_Directories_Config/expected-output.txt +++ b/tests/e2e/Source_Directories_Config/expected-output.txt @@ -2,6 +2,7 @@ Total: 1 Killed: 1 Errored: 0 +Syntax Errors: 0 Escaped: 0 Timed Out: 0 Skipped: 0 diff --git a/tests/e2e/SymfonyBridge/expected-output.txt b/tests/e2e/SymfonyBridge/expected-output.txt index 7bcb80de3..a31fc060f 100644 --- a/tests/e2e/SymfonyBridge/expected-output.txt +++ b/tests/e2e/SymfonyBridge/expected-output.txt @@ -2,6 +2,7 @@ Total: 1 Killed: 1 Errored: 0 +Syntax Errors: 0 Escaped: 0 Timed Out: 0 Skipped: 0 diff --git a/tests/e2e/SymfonyFlex/expected-output.txt b/tests/e2e/SymfonyFlex/expected-output.txt index 7bcb80de3..a31fc060f 100644 --- a/tests/e2e/SymfonyFlex/expected-output.txt +++ b/tests/e2e/SymfonyFlex/expected-output.txt @@ -2,6 +2,7 @@ Total: 1 Killed: 1 Errored: 0 +Syntax Errors: 0 Escaped: 0 Timed Out: 0 Skipped: 0 diff --git a/tests/e2e/Syntax_Error_PHPUnit/README.md b/tests/e2e/Syntax_Error_PHPUnit/README.md new file mode 100644 index 000000000..e5f27ff79 --- /dev/null +++ b/tests/e2e/Syntax_Error_PHPUnit/README.md @@ -0,0 +1,7 @@ +# Title + +* This test ensures that the results produced by Mutators that generate invalid syntax (with "syntax error") are treated separately + +## Summary + +Related to https://github.com/infection/infection/issues/262 diff --git a/tests/e2e/Syntax_Error_PHPUnit/composer.json b/tests/e2e/Syntax_Error_PHPUnit/composer.json new file mode 100644 index 000000000..8f49b60f7 --- /dev/null +++ b/tests/e2e/Syntax_Error_PHPUnit/composer.json @@ -0,0 +1,15 @@ +{ + "require-dev": { + "phpunit/phpunit": "^9.5.8" + }, + "autoload": { + "psr-4": { + "Syntax_Error_PHPUnit\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "Syntax_Error_PHPUnit\\Test\\": "tests/" + } + } +} diff --git a/tests/e2e/Syntax_Error_PHPUnit/expected-output.txt b/tests/e2e/Syntax_Error_PHPUnit/expected-output.txt new file mode 100644 index 000000000..b3a0bb786 --- /dev/null +++ b/tests/e2e/Syntax_Error_PHPUnit/expected-output.txt @@ -0,0 +1,9 @@ +Total: 1 + +Killed: 0 +Errored: 0 +Syntax Errors: 1 +Escaped: 0 +Timed Out: 0 +Skipped: 0 +Not Covered: 0 diff --git a/tests/e2e/Syntax_Error_PHPUnit/infection.json b/tests/e2e/Syntax_Error_PHPUnit/infection.json new file mode 100644 index 000000000..3164ffe15 --- /dev/null +++ b/tests/e2e/Syntax_Error_PHPUnit/infection.json @@ -0,0 +1,17 @@ +{ + "$schema": "../../../resources/schema.json", + "timeout": 25, + "source": { + "directories": [ + "src" + ] + }, + "logs": { + "summary": "infection.log" + }, + "tmpDir": ".", + "mutators": { + "@default": false, + "SyntaxError": true + } +} diff --git a/tests/e2e/Syntax_Error_PHPUnit/phpunit.xml b/tests/e2e/Syntax_Error_PHPUnit/phpunit.xml new file mode 100644 index 000000000..df138fe3f --- /dev/null +++ b/tests/e2e/Syntax_Error_PHPUnit/phpunit.xml @@ -0,0 +1,18 @@ + + + + + ./tests/ + + + + + + ./src/ + + + diff --git a/tests/e2e/Syntax_Error_PHPUnit/src/SourceClass.php b/tests/e2e/Syntax_Error_PHPUnit/src/SourceClass.php new file mode 100644 index 000000000..f92913337 --- /dev/null +++ b/tests/e2e/Syntax_Error_PHPUnit/src/SourceClass.php @@ -0,0 +1,16 @@ +foo(); + } +} diff --git a/tests/e2e/Syntax_Error_PHPUnit/tests/SourceClassTest.php b/tests/e2e/Syntax_Error_PHPUnit/tests/SourceClassTest.php new file mode 100644 index 000000000..ba2ac274d --- /dev/null +++ b/tests/e2e/Syntax_Error_PHPUnit/tests/SourceClassTest.php @@ -0,0 +1,15 @@ +assertSame('hello', $sourceClass->bar()); + } +} diff --git a/tests/e2e/Syntax_Error_Pest/README.md b/tests/e2e/Syntax_Error_Pest/README.md new file mode 100644 index 000000000..e5f27ff79 --- /dev/null +++ b/tests/e2e/Syntax_Error_Pest/README.md @@ -0,0 +1,7 @@ +# Title + +* This test ensures that the results produced by Mutators that generate invalid syntax (with "syntax error") are treated separately + +## Summary + +Related to https://github.com/infection/infection/issues/262 diff --git a/tests/e2e/Syntax_Error_Pest/composer.json b/tests/e2e/Syntax_Error_Pest/composer.json new file mode 100644 index 000000000..a41b55ed7 --- /dev/null +++ b/tests/e2e/Syntax_Error_Pest/composer.json @@ -0,0 +1,15 @@ +{ + "require-dev": { + "pestphp/pest": "^1.2.0" + }, + "autoload": { + "psr-4": { + "Syntax_Error_Pest\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "Syntax_Error_Pest\\Test\\": "tests/" + } + } +} diff --git a/tests/e2e/Syntax_Error_Pest/expected-output.txt b/tests/e2e/Syntax_Error_Pest/expected-output.txt new file mode 100644 index 000000000..b3a0bb786 --- /dev/null +++ b/tests/e2e/Syntax_Error_Pest/expected-output.txt @@ -0,0 +1,9 @@ +Total: 1 + +Killed: 0 +Errored: 0 +Syntax Errors: 1 +Escaped: 0 +Timed Out: 0 +Skipped: 0 +Not Covered: 0 diff --git a/tests/e2e/Syntax_Error_Pest/infection.json b/tests/e2e/Syntax_Error_Pest/infection.json new file mode 100644 index 000000000..3164ffe15 --- /dev/null +++ b/tests/e2e/Syntax_Error_Pest/infection.json @@ -0,0 +1,17 @@ +{ + "$schema": "../../../resources/schema.json", + "timeout": 25, + "source": { + "directories": [ + "src" + ] + }, + "logs": { + "summary": "infection.log" + }, + "tmpDir": ".", + "mutators": { + "@default": false, + "SyntaxError": true + } +} diff --git a/tests/e2e/Syntax_Error_Pest/phpunit.xml b/tests/e2e/Syntax_Error_Pest/phpunit.xml new file mode 100644 index 000000000..df138fe3f --- /dev/null +++ b/tests/e2e/Syntax_Error_Pest/phpunit.xml @@ -0,0 +1,18 @@ + + + + + ./tests/ + + + + + + ./src/ + + + diff --git a/tests/e2e/Syntax_Error_Pest/run_tests.bash b/tests/e2e/Syntax_Error_Pest/run_tests.bash new file mode 100755 index 000000000..949873a44 --- /dev/null +++ b/tests/e2e/Syntax_Error_Pest/run_tests.bash @@ -0,0 +1,14 @@ +#!/usr/bin/env bash + +readonly INFECTION="../../../bin/infection --test-framework=pest" + +set -e pipefail + +if [ "$DRIVER" = "phpdbg" ] +then + phpdbg -qrr $INFECTION +else + php $INFECTION +fi + +diff -w expected-output.txt infection.log diff --git a/tests/e2e/Syntax_Error_Pest/src/ForPest.php b/tests/e2e/Syntax_Error_Pest/src/ForPest.php new file mode 100644 index 000000000..6692b610f --- /dev/null +++ b/tests/e2e/Syntax_Error_Pest/src/ForPest.php @@ -0,0 +1,16 @@ +foo(); + } +} diff --git a/tests/e2e/Syntax_Error_Pest/tests/ForPestTest.php b/tests/e2e/Syntax_Error_Pest/tests/ForPestTest.php new file mode 100644 index 000000000..e12e6c83f --- /dev/null +++ b/tests/e2e/Syntax_Error_Pest/tests/ForPestTest.php @@ -0,0 +1,11 @@ +hello())->toBe('hello'); +}); diff --git a/tests/e2e/Test_Framework_Options_Config/expected-output.txt b/tests/e2e/Test_Framework_Options_Config/expected-output.txt index 7bcb80de3..a31fc060f 100644 --- a/tests/e2e/Test_Framework_Options_Config/expected-output.txt +++ b/tests/e2e/Test_Framework_Options_Config/expected-output.txt @@ -2,6 +2,7 @@ Total: 1 Killed: 1 Errored: 0 +Syntax Errors: 0 Escaped: 0 Timed Out: 0 Skipped: 0 diff --git a/tests/e2e/Test_PHP_Options_Config/expected-output.txt b/tests/e2e/Test_PHP_Options_Config/expected-output.txt index 7bcb80de3..a31fc060f 100644 --- a/tests/e2e/Test_PHP_Options_Config/expected-output.txt +++ b/tests/e2e/Test_PHP_Options_Config/expected-output.txt @@ -2,6 +2,7 @@ Total: 1 Killed: 1 Errored: 0 +Syntax Errors: 0 Escaped: 0 Timed Out: 0 Skipped: 0 diff --git a/tests/e2e/TimeoutSkipped/expected-output.txt b/tests/e2e/TimeoutSkipped/expected-output.txt index 4c78b02b4..129bf771f 100644 --- a/tests/e2e/TimeoutSkipped/expected-output.txt +++ b/tests/e2e/TimeoutSkipped/expected-output.txt @@ -2,6 +2,7 @@ Total: 5 Killed: 2 Errored: 0 +Syntax Errors: 0 Escaped: 2 Timed Out: 1 Skipped: 0 diff --git a/tests/e2e/Variables_Order_EGPCS/expected-output.txt b/tests/e2e/Variables_Order_EGPCS/expected-output.txt index 7bcb80de3..a31fc060f 100644 --- a/tests/e2e/Variables_Order_EGPCS/expected-output.txt +++ b/tests/e2e/Variables_Order_EGPCS/expected-output.txt @@ -2,6 +2,7 @@ Total: 1 Killed: 1 Errored: 0 +Syntax Errors: 0 Escaped: 0 Timed Out: 0 Skipped: 0 diff --git a/tests/e2e/YieldValue/expected-output.txt b/tests/e2e/YieldValue/expected-output.txt index 3c92154a1..1ce4f94ab 100644 --- a/tests/e2e/YieldValue/expected-output.txt +++ b/tests/e2e/YieldValue/expected-output.txt @@ -1,6 +1,6 @@ # Effects per Mutator -| Mutator | Mutations | Killed | Escaped | Errors | Timed Out | Skipped | MSI (%s) | Covered MSI (%s) | -| ---------- | --------- | ------ | ------- | ------ | --------- | ------- | -------- | ---------------- | -| YieldValue | 2 | 1 | 0 | 0 | 0 | 0 | 50.00 | 100.00 | -| Yield_ | 2 | 1 | 0 | 0 | 0 | 0 | 50.00 | 100.00 | +| Mutator | Mutations | Killed | Escaped | Errors | Syntax Errors | Timed Out | Skipped | MSI (%s) | Covered MSI (%s) | +| ---------- | --------- | ------ | ------- | ------ | ------------- | --------- | ------- | -------- | ---------------- | +| YieldValue | 2 | 1 | 0 | 0 | 0 | 0 | 0 | 50.00 | 100.00 | +| Yield_ | 2 | 1 | 0 | 0 | 0 | 0 | 0 | 50.00 | 100.00 | diff --git a/tests/phpunit/Console/OutputFormatter/DotFormatterTest.php b/tests/phpunit/Console/OutputFormatter/DotFormatterTest.php index 60f440f6f..fd6768c6f 100644 --- a/tests/phpunit/Console/OutputFormatter/DotFormatterTest.php +++ b/tests/phpunit/Console/OutputFormatter/DotFormatterTest.php @@ -58,6 +58,7 @@ public function test_start_logs_initial_starting_text(): void . 'M: escaped, ' . 'U: uncovered, ' . 'E: fatal error, ' + . 'X: syntax error, ' . 'T: timed out, ' . 'S: skipped', '', @@ -184,7 +185,7 @@ public function test_it_prints_total_number_of_mutations(): void $this->assertSame(str_replace("\n", PHP_EOL, <<<'TXT' -.: killed, M: escaped, U: uncovered, E: fatal error, T: timed out, S: skipped +.: killed, M: escaped, U: uncovered, E: fatal error, X: syntax error, T: timed out, S: skipped .................................................. ( 50 / 127) .................................................. (100 / 127) @@ -213,7 +214,7 @@ public function test_it_prints_current_number_of_pending_mutations(): void $this->assertSame(str_replace("\n", PHP_EOL, <<<'TXT' -.: killed, M: escaped, U: uncovered, E: fatal error, T: timed out, S: skipped +.: killed, M: escaped, U: uncovered, E: fatal error, X: syntax error, T: timed out, S: skipped .................................................. ( 50) .................................................. ( 100) @@ -252,6 +253,7 @@ private function getStartOutputFormatter() . 'M: escaped, ' . 'U: uncovered, ' . 'E: fatal error, ' + . 'X: syntax error, ' . 'T: timed out, ' . 'S: skipped', '', diff --git a/tests/phpunit/Console/OutputFormatterStyleConfiguratorTest.php b/tests/phpunit/Console/OutputFormatterStyleConfiguratorTest.php index ad0d7ad90..6c1214269 100644 --- a/tests/phpunit/Console/OutputFormatterStyleConfiguratorTest.php +++ b/tests/phpunit/Console/OutputFormatterStyleConfiguratorTest.php @@ -46,7 +46,7 @@ public function test_it_adds_styles(): void { $formatter = $this->createMock(OutputFormatterInterface::class); $formatter - ->expects($this->exactly(12)) + ->expects($this->exactly(13)) ->method('setStyle') ; diff --git a/tests/phpunit/Fixtures/TestFramework/DummyTestFrameworkAdapter.php b/tests/phpunit/Fixtures/TestFramework/DummyTestFrameworkAdapter.php index 7f2d982a7..c18dcf6bf 100644 --- a/tests/phpunit/Fixtures/TestFramework/DummyTestFrameworkAdapter.php +++ b/tests/phpunit/Fixtures/TestFramework/DummyTestFrameworkAdapter.php @@ -5,6 +5,7 @@ namespace Infection\Tests\Fixtures\TestFramework; use Infection\AbstractTestFramework\TestFrameworkAdapter; +use Infection\AbstractTestFramework\UnsupportedTestFrameworkVersion; final class DummyTestFrameworkAdapter implements TestFrameworkAdapter { diff --git a/tests/phpunit/Logger/CreateMetricsCalculator.php b/tests/phpunit/Logger/CreateMetricsCalculator.php index 7d3dc21fa..70eabdda4 100644 --- a/tests/phpunit/Logger/CreateMetricsCalculator.php +++ b/tests/phpunit/Logger/CreateMetricsCalculator.php @@ -93,6 +93,18 @@ private function feedCollector(Collector $collector): void DetectionStatus::ERROR, 'error#1' ), + $this->createMutantExecutionResult( + 0, + For_::class, + DetectionStatus::SYNTAX_ERROR, + 'syntaxError#0' + ), + $this->createMutantExecutionResult( + 1, + PregQuote::class, + DetectionStatus::SYNTAX_ERROR, + 'syntaxError#1' + ), $this->createMutantExecutionResult( 0, For_::class, diff --git a/tests/phpunit/Logger/DebugFileLoggerTest.php b/tests/phpunit/Logger/DebugFileLoggerTest.php index cbf9f63ef..bbe286361 100644 --- a/tests/phpunit/Logger/DebugFileLoggerTest.php +++ b/tests/phpunit/Logger/DebugFileLoggerTest.php @@ -74,6 +74,9 @@ public function metricsProvider(): iterable Errors mutants: =============== +Syntax Errors mutants: +====================== + Escaped mutants: ================ @@ -94,7 +97,7 @@ public function metricsProvider(): iterable $this->createCompleteResultsCollector(), false, <<<'TXT' -Total: 12 +Total: 14 Killed mutants: =============== @@ -116,6 +119,16 @@ public function metricsProvider(): iterable Line 10 +Syntax Errors mutants: +====================== + +Mutator: PregQuote +Line 9 + +Mutator: For_ +Line 10 + + Escaped mutants: ================ @@ -163,7 +176,7 @@ public function metricsProvider(): iterable $this->createCompleteResultsCollector(), true, <<<'TXT' -Total: 12 +Total: 14 Killed mutants: =============== @@ -185,6 +198,16 @@ public function metricsProvider(): iterable Line 10 +Syntax Errors mutants: +====================== + +Mutator: PregQuote +Line 9 + +Mutator: For_ +Line 10 + + Escaped mutants: ================ diff --git a/tests/phpunit/Logger/JsonLoggerTest.php b/tests/phpunit/Logger/JsonLoggerTest.php index a4d1f933e..f3fc9c0db 100644 --- a/tests/phpunit/Logger/JsonLoggerTest.php +++ b/tests/phpunit/Logger/JsonLoggerTest.php @@ -82,6 +82,7 @@ public function metricsProvider(): iterable 'notCoveredCount' => 0, 'escapedCount' => 0, 'errorCount' => 0, + 'syntaxErrorCount' => 0, 'skippedCount' => 0, 'timeOutCount' => 0, 'msi' => 0, @@ -92,6 +93,7 @@ public function metricsProvider(): iterable 'timeouted' => [], 'killed' => [], 'errored' => [], + 'syntaxErrors' => [], 'uncovered' => [], ], ]; @@ -102,16 +104,17 @@ public function metricsProvider(): iterable $this->createCompleteResultsCollector(), [ 'stats' => [ - 'totalMutantsCount' => 12, + 'totalMutantsCount' => 14, 'killedCount' => 2, 'notCoveredCount' => 2, 'escapedCount' => 2, 'errorCount' => 2, + 'syntaxErrorCount' => 2, 'skippedCount' => 2, 'timeOutCount' => 2, - 'msi' => 60, - 'mutationCodeCoverage' => 80, - 'coveredCodeMsi' => 75, + 'msi' => 50, + 'mutationCodeCoverage' => 83.33, + 'coveredCodeMsi' => 60, ], 'escaped' => [ [ @@ -209,6 +212,30 @@ public function metricsProvider(): iterable 'processOutput' => 'process output', ], ], + 'syntaxErrors' => [ + [ + 'mutator' => [ + 'mutatorName' => 'PregQuote', + 'originalSourceCode' => ' ' 'foo/bar', + 'originalStartLine' => 9, + ], + 'diff' => str_replace("\n", PHP_EOL, "--- Original\n+++ New\n@@ @@\n\n- echo 'original';\n+ echo 'syntaxError#1';"), + 'processOutput' => 'process output', + ], + [ + 'mutator' => [ + 'mutatorName' => 'For_', + 'originalSourceCode' => ' ' 'foo/bar', + 'originalStartLine' => 10, + ], + 'diff' => str_replace("\n", PHP_EOL, "--- Original\n+++ New\n@@ @@\n\n- echo 'original';\n+ echo 'syntaxError#0';"), + 'processOutput' => 'process output', + ], + ], 'uncovered' => [], ], ]; @@ -224,6 +251,7 @@ public function metricsProvider(): iterable 'notCoveredCount' => 1, 'escapedCount' => 0, 'errorCount' => 0, + 'syntaxErrorCount' => 0, 'skippedCount' => 0, 'timeOutCount' => 0, 'msi' => 0, @@ -234,6 +262,7 @@ public function metricsProvider(): iterable 'timeouted' => [], 'killed' => [], 'errored' => [], + 'syntaxErrors' => [], 'uncovered' => [ [ 'mutator' => [ @@ -261,6 +290,7 @@ public function metricsProvider(): iterable 'notCoveredCount' => 0, 'escapedCount' => 0, 'errorCount' => 0, + 'syntaxErrorCount' => 0, 'skippedCount' => 0, 'timeOutCount' => 0, 'msi' => 0, @@ -271,6 +301,7 @@ public function metricsProvider(): iterable 'timeouted' => [], 'killed' => [], 'errored' => [], + 'syntaxErrors' => [], 'uncovered' => [ [ 'mutator' => [ diff --git a/tests/phpunit/Logger/PerMutatorLoggerTest.php b/tests/phpunit/Logger/PerMutatorLoggerTest.php index 22e484004..d9a9262ba 100644 --- a/tests/phpunit/Logger/PerMutatorLoggerTest.php +++ b/tests/phpunit/Logger/PerMutatorLoggerTest.php @@ -66,8 +66,8 @@ public function metricsProvider(): iterable <<<'TXT' # Effects per Mutator -| Mutator | Mutations | Killed | Escaped | Errors | Timed Out | Skipped | MSI (%s) | Covered MSI (%s) | -| ------- | --------- | ------ | ------- | ------ | --------- | ------- | -------- | ---------------- | +| Mutator | Mutations | Killed | Escaped | Errors | Syntax Errors | Timed Out | Skipped | MSI (%s) | Covered MSI (%s) | +| ------- | --------- | ------ | ------- | ------ | ------------- | --------- | ------- | -------- | ---------------- | TXT ]; @@ -78,10 +78,10 @@ public function metricsProvider(): iterable <<<'TXT' # Effects per Mutator -| Mutator | Mutations | Killed | Escaped | Errors | Timed Out | Skipped | MSI (%s) | Covered MSI (%s) | -| --------- | --------- | ------ | ------- | ------ | --------- | ------- | -------- | ---------------- | -| For_ | 6 | 1 | 1 | 1 | 1 | 1 | 60.00 | 75.00 | -| PregQuote | 6 | 1 | 1 | 1 | 1 | 1 | 60.00 | 75.00 | +| Mutator | Mutations | Killed | Escaped | Errors | Syntax Errors | Timed Out | Skipped | MSI (%s) | Covered MSI (%s) | +| --------- | --------- | ------ | ------- | ------ | ------------- | --------- | ------- | -------- | ---------------- | +| For_ | 7 | 1 | 1 | 1 | 1 | 1 | 1 | 50.00 | 60.00 | +| PregQuote | 7 | 1 | 1 | 1 | 1 | 1 | 1 | 50.00 | 60.00 | TXT ]; diff --git a/tests/phpunit/Logger/SummaryFileLoggerTest.php b/tests/phpunit/Logger/SummaryFileLoggerTest.php index 9cf38cb51..3abb453e5 100644 --- a/tests/phpunit/Logger/SummaryFileLoggerTest.php +++ b/tests/phpunit/Logger/SummaryFileLoggerTest.php @@ -65,6 +65,7 @@ public function metricsProvider(): iterable Killed: 0 Errored: 0 +Syntax Errors: 0 Escaped: 0 Timed Out: 0 Skipped: 0 @@ -76,10 +77,11 @@ public function metricsProvider(): iterable yield 'all mutations' => [ $this->createCompleteMetricsCalculator(), <<<'TXT' -Total: 12 +Total: 14 Killed: 2 Errored: 2 +Syntax Errors: 2 Escaped: 2 Timed Out: 2 Skipped: 2 diff --git a/tests/phpunit/Logger/TextFileLoggerTest.php b/tests/phpunit/Logger/TextFileLoggerTest.php index 1f51a393a..34bb866aa 100644 --- a/tests/phpunit/Logger/TextFileLoggerTest.php +++ b/tests/phpunit/Logger/TextFileLoggerTest.php @@ -124,6 +124,9 @@ public function emptyMetricsProvider(): iterable Errors mutants: =============== +Syntax Errors mutants: +====================== + Not Covered mutants: ==================== @@ -170,6 +173,9 @@ public function emptyMetricsProvider(): iterable Errors mutants: =============== +Syntax Errors mutants: +====================== + Not Covered mutants: ==================== @@ -213,6 +219,9 @@ public function emptyMetricsProvider(): iterable Errors mutants: =============== +Syntax Errors mutants: +====================== + TXT ]; @@ -253,6 +262,9 @@ public function emptyMetricsProvider(): iterable Errors mutants: =============== +Syntax Errors mutants: +====================== + TXT ]; } @@ -498,6 +510,33 @@ public function completeMetricsProvider(): iterable process output +Syntax Errors mutants: +====================== + +1) foo/bar:9 [M] PregQuote + +--- Original ++++ New +@@ @@ + +- echo 'original'; ++ echo 'syntaxError#1'; + + process output + + +2) foo/bar:10 [M] For_ + +--- Original ++++ New +@@ @@ + +- echo 'original'; ++ echo 'syntaxError#0'; + + process output + + Not Covered mutants: ==================== @@ -792,6 +831,35 @@ public function completeMetricsProvider(): iterable process output +Syntax Errors mutants: +====================== + +1) foo/bar:9 [M] PregQuote + +--- Original ++++ New +@@ @@ + +- echo 'original'; ++ echo 'syntaxError#1'; + +$ bin/phpunit --configuration infection-tmp-phpunit.xml --filter "tests/Acme/FooTest.php" + process output + + +2) foo/bar:10 [M] For_ + +--- Original ++++ New +@@ @@ + +- echo 'original'; ++ echo 'syntaxError#0'; + +$ bin/phpunit --configuration infection-tmp-phpunit.xml --filter "tests/Acme/FooTest.php" + process output + + Not Covered mutants: ==================== @@ -1038,6 +1106,33 @@ public function completeMetricsProvider(): iterable process output + +Syntax Errors mutants: +====================== + +1) foo/bar:9 [M] PregQuote + +--- Original ++++ New +@@ @@ + +- echo 'original'; ++ echo 'syntaxError#1'; + + process output + + +2) foo/bar:10 [M] For_ + +--- Original ++++ New +@@ @@ + +- echo 'original'; ++ echo 'syntaxError#0'; + + process output + TXT ]; @@ -1275,6 +1370,35 @@ public function completeMetricsProvider(): iterable - echo 'original'; + echo 'error#0'; +$ bin/phpunit --configuration infection-tmp-phpunit.xml --filter "tests/Acme/FooTest.php" + process output + + +Syntax Errors mutants: +====================== + +1) foo/bar:9 [M] PregQuote + +--- Original ++++ New +@@ @@ + +- echo 'original'; ++ echo 'syntaxError#1'; + +$ bin/phpunit --configuration infection-tmp-phpunit.xml --filter "tests/Acme/FooTest.php" + process output + + +2) foo/bar:10 [M] For_ + +--- Original ++++ New +@@ @@ + +- echo 'original'; ++ echo 'syntaxError#0'; + $ bin/phpunit --configuration infection-tmp-phpunit.xml --filter "tests/Acme/FooTest.php" process output diff --git a/tests/phpunit/Metrics/CalculatorTest.php b/tests/phpunit/Metrics/CalculatorTest.php index 7919f7cd0..cfd726cfa 100644 --- a/tests/phpunit/Metrics/CalculatorTest.php +++ b/tests/phpunit/Metrics/CalculatorTest.php @@ -174,9 +174,9 @@ public function metricsCalculatorProvider(): iterable yield 'nominal' => [ $this->createCompleteMetricsCalculator(), - 60., - 80.0, - 75.0, + 50., // 14 total mutations; 2 skipped; 6 of 12 are killed => 50% + 83.33, // 14 total mutations; 2 skipped & 2 not covered; => 10 of 12 => 83.33% + 60.0, // 14 total mutations; 2 skipped & 2 not covered; 6 of 10 are killed => 60% ]; } } diff --git a/tests/phpunit/Mutator/BaseMutatorTestCase.php b/tests/phpunit/Mutator/BaseMutatorTestCase.php index 27a85b3e9..54cc9e150 100644 --- a/tests/phpunit/Mutator/BaseMutatorTestCase.php +++ b/tests/phpunit/Mutator/BaseMutatorTestCase.php @@ -70,7 +70,7 @@ protected function setUp(): void * @var string|string[] * @var mixed[] $settings */ - final public function doTest(string $inputCode, $expectedCode = [], array $settings = []): void + final public function doTest(string $inputCode, $expectedCode = [], array $settings = [], bool $allowInvalidCode = false): void { $expectedCodeSamples = (array) $expectedCode; @@ -106,7 +106,10 @@ final public function doTest(string $inputCode, $expectedCode = [], array $setti StringNormalizer::normalizeString($expectedCodeSample), StringNormalizer::normalizeString($realMutatedCode) ); - $this->assertSyntaxIsValid($realMutatedCode); + + if (!$allowInvalidCode) { + $this->assertSyntaxIsValid($realMutatedCode); + } } } diff --git a/tests/phpunit/Mutator/ProfileListProvider.php b/tests/phpunit/Mutator/ProfileListProvider.php index ada99f0ae..9dbc81850 100644 --- a/tests/phpunit/Mutator/ProfileListProvider.php +++ b/tests/phpunit/Mutator/ProfileListProvider.php @@ -44,6 +44,7 @@ use Infection\Mutator\Mutator; use Infection\Mutator\NoopMutator; use Infection\Mutator\ProfileList; +use Infection\Mutator\SyntaxError; use ReflectionClass; use function Safe\ksort; use function Safe\realpath; @@ -98,7 +99,7 @@ public static function implementedMutatorProvider(): iterable $shortClassName = substr($file->getFilename(), 0, -4); $className = self::getMutatorClassNameFromPath($file->getPathname()); - if (in_array($className, [IgnoreMutator::class, NoopMutator::class], true)) { + if (in_array($className, [IgnoreMutator::class, NoopMutator::class, SyntaxError::class], true)) { continue; } diff --git a/tests/phpunit/Mutator/SyntaxErrorTest.php b/tests/phpunit/Mutator/SyntaxErrorTest.php new file mode 100644 index 000000000..5916197c4 --- /dev/null +++ b/tests/phpunit/Mutator/SyntaxErrorTest.php @@ -0,0 +1,66 @@ +doTest($input, $expected, [], true); + } + + public function mutationsProvider(): iterable + { + yield 'It mutates method call to invalid syntax' => [ + <<<'PHP' +methodCall(); +PHP + , + <<<'PHP' +methodCall(); +PHP + ]; + } +} diff --git a/tests/phpunit/TestFramework/PhpUnit/Adapter/PestAdapterTest.php b/tests/phpunit/TestFramework/PhpUnit/Adapter/PestAdapterTest.php index bc5c85802..69ccfb90d 100644 --- a/tests/phpunit/TestFramework/PhpUnit/Adapter/PestAdapterTest.php +++ b/tests/phpunit/TestFramework/PhpUnit/Adapter/PestAdapterTest.php @@ -91,9 +91,9 @@ public function test_it_supports_junit_reports(): void } /** - * @dataProvider outputProvider + * @dataProvider passOutputProvider */ - public function test_it_can_tell_the_outcome_of_the_tests_from_the_output( + public function test_it_can_tell_if_tests_pass_from_the_output( string $output, bool $expected ): void { @@ -102,6 +102,18 @@ public function test_it_can_tell_the_outcome_of_the_tests_from_the_output( $this->assertSame($expected, $actual); } + /** + * @dataProvider syntaxErrorOutputProvider + */ + public function test_it_can_tell_if_there_is_a_syntax_error_from_the_output( + string $output, + bool $expected + ): void { + $actual = $this->adapter->isSyntaxError($output); + + $this->assertSame($expected, $actual); + } + /** * @dataProvider memoryReportProvider */ @@ -266,7 +278,7 @@ public function test_it_provides_initial_test_run_command_line_when_coverage_rep ); } - public function outputProvider(): iterable + public function passOutputProvider(): iterable { yield ['Tests: 1 risked', true]; @@ -275,6 +287,21 @@ public function outputProvider(): iterable yield ['Tests: 1 failed, 8 passed', false]; } + public function syntaxErrorOutputProvider(): iterable + { + yield ['Tests: 1 risked', false]; + + yield [ + <<"' +TXT + , + true, + ]; + } + public function memoryReportProvider(): iterable { yield ['Memory: 8.00MB', 8.0]; diff --git a/tests/phpunit/TestFramework/PhpUnit/Adapter/PhpUnitAdapterTest.php b/tests/phpunit/TestFramework/PhpUnit/Adapter/PhpUnitAdapterTest.php index eb9d9b56e..ce718c2d0 100644 --- a/tests/phpunit/TestFramework/PhpUnit/Adapter/PhpUnitAdapterTest.php +++ b/tests/phpunit/TestFramework/PhpUnit/Adapter/PhpUnitAdapterTest.php @@ -91,9 +91,9 @@ public function test_it_supports_junit_reports(): void } /** - * @dataProvider outputProvider + * @dataProvider passOutputProvider */ - public function test_it_can_tell_the_outcome_of_the_tests_from_the_output( + public function test_it_can_tell_if_tests_pass_from_the_output( string $output, bool $expected ): void { @@ -102,6 +102,18 @@ public function test_it_can_tell_the_outcome_of_the_tests_from_the_output( $this->assertSame($expected, $actual); } + /** + * @dataProvider syntaxErrorOutputProvider + */ + public function test_it_can_tell_if_there_is_a_syntax_error_from_the_output( + string $output, + bool $expected + ): void { + $actual = $this->adapter->isSyntaxError($output); + + $this->assertSame($expected, $actual); + } + /** * @dataProvider memoryReportProvider */ @@ -266,7 +278,7 @@ public function test_it_provides_initial_test_run_command_line_when_coverage_rep ); } - public function outputProvider(): iterable + public function passOutputProvider(): iterable { yield ['OK, but incomplete, skipped, or risky tests!', true]; @@ -279,6 +291,13 @@ public function outputProvider(): iterable yield ['No tests executed!', true]; } + public function syntaxErrorOutputProvider(): iterable + { + yield ['OK, but incomplete, skipped, or risky tests!', false]; + + yield ['ParseError: syntax error, unexpected ">"', true]; + } + public function memoryReportProvider(): iterable { yield ['Memory: 8.00MB', 8.0];