diff --git a/bin/pest-wrapper.php b/bin/pest-wrapper.php index e69de29b..2d339284 100644 --- a/bin/pest-wrapper.php +++ b/bin/pest-wrapper.php @@ -0,0 +1,91 @@ + false]); + assert(is_array($phpunitArgv)); + + /** + * We need to instantiate the Pest Test suite instance + * so that Pest is able to execute correctly. + */ + $argv = new ArgvInput(); + $rootPath = dirname(PHPUNIT_COMPOSER_INSTALL, 2); + TestSuite::getInstance( + $rootPath, + $argv->getParameterOption('--test-directory', (new ConfigLoader($rootPath))->getTestsDirectory()), + ); + + $application = new ApplicationForWrapperWorker( + $phpunitArgv, + $getopt['progress-file'], + $getopt['testresult-file'], + $getopt['teamcity-file'] ?? null, + $getopt['testdox-file'] ?? null, + isset($getopt['testdox-color']), + ); + + while (true) { + if (feof(STDIN)) { + $application->end(); + exit; + } + + $testPath = fgets(STDIN); + if ($testPath === false || $testPath === WrapperWorker::COMMAND_EXIT) { + $application->end(); + exit; + } + + // It must be a 1 byte string to ensure filesize() is equal to the number of tests executed + $exitCode = $application->runTest(trim($testPath)); + + fwrite($statusFile, (string) $exitCode); + fflush($statusFile); + } +})(); diff --git a/src/Plugins/Parallel/Paratest/WrapperRunner.php b/src/Plugins/Parallel/Paratest/WrapperRunner.php index 55873d8c..2ce4a13b 100644 --- a/src/Plugins/Parallel/Paratest/WrapperRunner.php +++ b/src/Plugins/Parallel/Paratest/WrapperRunner.php @@ -12,6 +12,7 @@ use ParaTest\RunnerInterface; use ParaTest\WrapperRunner\ResultPrinter; use ParaTest\WrapperRunner\SuiteLoader; use ParaTest\WrapperRunner\WrapperWorker; +use Pest\TestSuite; use PHPUnit\Event\Facade as EventFacade; use PHPUnit\Runner\CodeCoverage; use PHPUnit\TestRunner\TestResult\Facade as TestResultFacade; @@ -31,6 +32,7 @@ use function dirname; use function file_get_contents; use function max; use function realpath; +use function unlink; use function unserialize; use function usleep; @@ -50,15 +52,15 @@ final class WrapperRunner implements RunnerInterface /** @var array */ private array $batches = []; - /** @var SplFileInfo */ + /** @var list */ private array $testresultFiles = []; - /** @var SplFileInfo */ + /** @var list */ private array $coverageFiles = []; - /** @var SplFileInfo */ + /** @var list */ private array $junitFiles = []; - /** @var SplFileInfo */ + /** @var list */ private array $teamcityFiles = []; - /** @var SplFileInfo */ + /** @var list */ private array $testdoxFiles = []; /** @var non-empty-string[] */ @@ -71,7 +73,7 @@ final class WrapperRunner implements RunnerInterface $this->printer = new ResultPrinter($output, $options); $wrapper = realpath( - dirname(__DIR__, 5) . DIRECTORY_SEPARATOR . 'bin' . DIRECTORY_SEPARATOR . 'phpunit-wrapper.php', + dirname(__DIR__, 4) . DIRECTORY_SEPARATOR . 'bin' . DIRECTORY_SEPARATOR . 'pest-wrapper.php', ); assert($wrapper !== false); $phpFinder = new PhpExecutableFinder(); @@ -89,21 +91,23 @@ final class WrapperRunner implements RunnerInterface $this->parameters = $parameters; } - public function run(): void + public function run(): int { ExcludeList::addDirectory(dirname(__DIR__)); TestResultFacade::init(); EventFacade::seal(); $suiteLoader = new SuiteLoader($this->options, $this->output); + $this->pending = $this->getTestFiles($suiteLoader); + $result = TestResultFacade::result(); - $this->pending = $suiteLoader->files; $this->printer->setTestCount($suiteLoader->testCount); $this->printer->start(); $this->startWorkers(); $this->assignAllPendingTests(); $this->waitForAllToFinish(); - $this->complete($result); + + return $this->complete($result); } public function getExitCode(): int @@ -141,10 +145,7 @@ final class WrapperRunner implements RunnerInterface if ( $this->exitcode > 0 - && ( - $this->options->configuration->stopOnFailure() - || $this->options->configuration->stopOnError() - ) + && $this->options->configuration->stopOnFailure() ) { $this->pending = []; } elseif (($pending = array_shift($this->pending)) !== null) { @@ -160,7 +161,10 @@ final class WrapperRunner implements RunnerInterface private function flushWorker(WrapperWorker $worker): void { $this->exitcode = max($this->exitcode, $worker->getExitCode()); - $this->printer->printFeedback($worker->progressFile); + $this->printer->printFeedback( + $worker->progressFile, + $this->teamcityFiles, + ); $worker->reset(); } @@ -232,7 +236,7 @@ final class WrapperRunner implements RunnerInterface unset($this->workers[$token]); } - private function complete(TestResult $testResultSum): void + private function complete(TestResult $testResultSum): int { foreach ($this->testresultFiles as $testresultFile) { if (! $testresultFile->isFile()) { @@ -251,6 +255,7 @@ final class WrapperRunner implements RunnerInterface array_merge_recursive($testResultSum->testErroredEvents(), $testResult->testErroredEvents()), array_merge_recursive($testResultSum->testFailedEvents(), $testResult->testFailedEvents()), array_merge_recursive($testResultSum->testConsideredRiskyEvents(), $testResult->testConsideredRiskyEvents()), + array_merge_recursive($testResultSum->testSuiteSkippedEvents(), $testResult->testSuiteSkippedEvents()), array_merge_recursive($testResultSum->testSkippedEvents(), $testResult->testSkippedEvents()), array_merge_recursive($testResultSum->testMarkedIncompleteEvents(), $testResult->testMarkedIncompleteEvents()), array_merge_recursive($testResultSum->testTriggeredDeprecationEvents(), $testResult->testTriggeredDeprecationEvents()), @@ -268,11 +273,15 @@ final class WrapperRunner implements RunnerInterface ); } - $this->printer->printResults($testResultSum); + $this->printer->printResults( + $testResultSum, + $this->teamcityFiles, + $this->testdoxFiles, + ); $this->generateCodeCoverageReports(); $this->generateLogs(); - $this->exitcode = (new ShellExitCodeCalculator())->calculate( + $exitcode = (new ShellExitCodeCalculator())->calculate( $this->options->configuration->failOnEmptyTestSuite(), $this->options->configuration->failOnRisky(), $this->options->configuration->failOnWarning(), @@ -280,6 +289,14 @@ final class WrapperRunner implements RunnerInterface $this->options->configuration->failOnSkipped(), $testResultSum, ); + + $this->clearFiles($this->testresultFiles); + $this->clearFiles($this->coverageFiles); + $this->clearFiles($this->junitFiles); + $this->clearFiles($this->teamcityFiles); + $this->clearFiles($this->testdoxFiles); + + return $exitcode; } protected function generateCodeCoverageReports(): void @@ -312,4 +329,33 @@ final class WrapperRunner implements RunnerInterface $this->options->configuration->logfileJunit(), ); } + + /** @param list $files */ + private function clearFiles(array $files): void + { + foreach ($files as $file) { + if (! $file->isFile()) { + continue; + } + + unlink($file->getPathname()); + } + } + + private function getTestFiles(SuiteLoader $suiteLoader): array + { + /** + * TODO: Clean this up + * + * We are doing this because the SuiteLoader returns filenames incorrectly + * for Pest tests. We need to find a better way to do this. + */ + + $tests = array_filter( + $suiteLoader->files, + fn(string $filename) => ! str_ends_with($filename, "eval()'d code") + ); + + return [...$tests, ...TestSuite::getInstance()->tests->getFilenames()]; + } }