package and depencies
This commit is contained in:
		| @@ -44,12 +44,14 @@ class CollisionServiceProvider extends ServiceProvider | ||||
|      */ | ||||
|     public function register() | ||||
|     { | ||||
|         if ($this->app->runningInConsole() && !$this->app->runningUnitTests()) { | ||||
|         if ($this->app->runningInConsole() && ! $this->app->runningUnitTests()) { | ||||
|             $this->app->bind(ProviderContract::class, function () { | ||||
|                 if ($this->app->has(\Facade\IgnitionContracts\SolutionProviderRepository::class)) { | ||||
|                     $solutionsRepository = new IgnitionSolutionsRepository( | ||||
|                         $this->app->get(\Facade\IgnitionContracts\SolutionProviderRepository::class) | ||||
|                     ); | ||||
|                 // @phpstan-ignore-next-line | ||||
|                 if ($this->app->has(\Spatie\Ignition\Contracts\SolutionProviderRepository::class)) { | ||||
|                     /** @var \Spatie\Ignition\Contracts\SolutionProviderRepository $solutionProviderRepository */ | ||||
|                     $solutionProviderRepository = $this->app->get(\Spatie\Ignition\Contracts\SolutionProviderRepository::class); | ||||
|  | ||||
|                     $solutionsRepository = new IgnitionSolutionsRepository($solutionProviderRepository); | ||||
|                 } else { | ||||
|                     $solutionsRepository = new NullSolutionsRepository(); | ||||
|                 } | ||||
| @@ -60,6 +62,7 @@ class CollisionServiceProvider extends ServiceProvider | ||||
|                 return new Provider(null, $handler); | ||||
|             }); | ||||
|  | ||||
|             /** @var \Illuminate\Contracts\Debug\ExceptionHandler $appExceptionHandler */ | ||||
|             $appExceptionHandler = $this->app->make(ExceptionHandlerContract::class); | ||||
|  | ||||
|             $this->app->singleton( | ||||
|   | ||||
| @@ -11,6 +11,7 @@ use Illuminate\Console\Command; | ||||
| use Illuminate\Support\Env; | ||||
| use Illuminate\Support\Str; | ||||
| use NunoMaduro\Collision\Adapters\Laravel\Exceptions\RequirementsException; | ||||
| use NunoMaduro\Collision\Coverage; | ||||
| use RuntimeException; | ||||
| use Symfony\Component\Process\Exception\ProcessSignaledException; | ||||
| use Symfony\Component\Process\Process; | ||||
| @@ -29,8 +30,11 @@ class TestCommand extends Command | ||||
|      */ | ||||
|     protected $signature = 'test | ||||
|         {--without-tty : Disable output to TTY} | ||||
|         {--coverage : Indicates whether code coverage information should be collected} | ||||
|         {--min= : Indicates the minimum threshold enforcement for code coverage} | ||||
|         {--p|parallel : Indicates if the tests should run in parallel} | ||||
|         {--recreate-databases : Indicates if the test databases should be re-created} | ||||
|         {--drop-databases : Indicates if the test databases should be dropped} | ||||
|     '; | ||||
|  | ||||
|     /** | ||||
| @@ -59,17 +63,38 @@ class TestCommand extends Command | ||||
|      */ | ||||
|     public function handle() | ||||
|     { | ||||
|         if ((int) \PHPUnit\Runner\Version::id()[0] < 9) { | ||||
|             throw new RequirementsException('Running Collision ^5.0 artisan test command requires at least PHPUnit ^9.0.'); | ||||
|         $phpunitVersion = \PHPUnit\Runner\Version::id(); | ||||
|  | ||||
|         if ((int) $phpunitVersion[0] === 1) { | ||||
|             throw new RequirementsException('Running PHPUnit 10.x or Pest 2.x requires Collision 7.x.'); | ||||
|         } | ||||
|  | ||||
|         if ((int) $phpunitVersion[0] < 9) { | ||||
|             throw new RequirementsException('Running Collision 6.x artisan test command requires at least PHPUnit 9.x.'); | ||||
|         } | ||||
|  | ||||
|         $laravelVersion = (int) \Illuminate\Foundation\Application::VERSION; | ||||
|  | ||||
|         // @phpstan-ignore-next-line | ||||
|         if ((int) \Illuminate\Foundation\Application::VERSION[0] < 8) { | ||||
|             throw new RequirementsException('Running Collision ^5.0 artisan test command requires at least Laravel ^8.0.'); | ||||
|         if ($laravelVersion < 9) { | ||||
|             throw new RequirementsException('Running Collision 6.x artisan test command requires at least Laravel 9.x.'); | ||||
|         } | ||||
|  | ||||
|         if ($this->option('parallel') && !$this->isParallelDependenciesInstalled()) { | ||||
|             if (!$this->confirm('Running tests in parallel requires "brianium/paratest". Do you wish to install it as a dev dependency?')) { | ||||
|         if ($this->option('coverage') && ! Coverage::isAvailable()) { | ||||
|             $this->output->writeln(sprintf( | ||||
|                 "\n  <fg=white;bg=red;options=bold> ERROR </> Code coverage driver not available.%s</>", | ||||
|                 Coverage::usingXdebug() | ||||
|                     ? " Did you set <href=https://xdebug.org/docs/code_coverage#mode>Xdebug's coverage mode</>?" | ||||
|                     : '' | ||||
|             )); | ||||
|  | ||||
|             $this->newLine(); | ||||
|  | ||||
|             return 1; | ||||
|         } | ||||
|  | ||||
|         if ($this->option('parallel') && ! $this->isParallelDependenciesInstalled()) { | ||||
|             if (! $this->confirm('Running tests in parallel requires "brianium/paratest". Do you wish to install it as a dev dependency?')) { | ||||
|                 return 1; | ||||
|             } | ||||
|  | ||||
| @@ -83,24 +108,26 @@ class TestCommand extends Command | ||||
|         $parallel = $this->option('parallel'); | ||||
|  | ||||
|         $process = (new Process(array_merge( | ||||
|                 // Binary ... | ||||
|                 $this->binary(), | ||||
|                 // Arguments ... | ||||
|                 $parallel ? $this->paratestArguments($options) : $this->phpunitArguments($options) | ||||
|             ), | ||||
|             // Binary ... | ||||
|             $this->binary(), | ||||
|             // Arguments ... | ||||
|             $parallel ? $this->paratestArguments($options) : $this->phpunitArguments($options) | ||||
|         ), | ||||
|             null, | ||||
|             // Envs ... | ||||
|             $parallel ? $this->paratestEnvironmentVariables() : $this->phpunitEnvironmentVariables(), | ||||
|         ))->setTimeout(null); | ||||
|  | ||||
|         try { | ||||
|             $process->setTty(!$this->option('without-tty')); | ||||
|             $process->setTty(! $this->option('without-tty')); | ||||
|         } catch (RuntimeException $e) { | ||||
|             $this->output->writeln('Warning: ' . $e->getMessage()); | ||||
|             $this->output->writeln('Warning: '.$e->getMessage()); | ||||
|         } | ||||
|  | ||||
|         $exitCode = 1; | ||||
|  | ||||
|         try { | ||||
|             return $process->run(function ($type, $line) { | ||||
|             $exitCode = $process->run(function ($type, $line) { | ||||
|                 $this->output->write($line); | ||||
|             }); | ||||
|         } catch (ProcessSignaledException $e) { | ||||
| @@ -108,6 +135,28 @@ class TestCommand extends Command | ||||
|                 throw $e; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if ($exitCode === 0 && $this->option('coverage')) { | ||||
|             if (! $this->usingPest() && $this->option('parallel')) { | ||||
|                 $this->newLine(); | ||||
|             } | ||||
|  | ||||
|             $coverage = Coverage::report($this->output); | ||||
|  | ||||
|             $exitCode = (int) ($coverage < $this->option('min')); | ||||
|  | ||||
|             if ($exitCode === 1) { | ||||
|                 $this->output->writeln(sprintf( | ||||
|                     "\n  <fg=white;bg=red;options=bold> FAIL </> Code coverage below expected:<fg=red;options=bold> %s %%</>. Minimum:<fg=white;options=bold> %s %%</>.", | ||||
|                     number_format($coverage, 1), | ||||
|                     number_format((float) $this->option('min'), 1) | ||||
|                 )); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         $this->newLine(); | ||||
|  | ||||
|         return $exitCode; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
| @@ -117,7 +166,7 @@ class TestCommand extends Command | ||||
|      */ | ||||
|     protected function binary() | ||||
|     { | ||||
|         if (class_exists(\Pest\Laravel\PestServiceProvider::class)) { | ||||
|         if ($this->usingPest()) { | ||||
|             $command = $this->option('parallel') ? ['vendor/pestphp/pest/bin/pest', '--parallel'] : ['vendor/pestphp/pest/bin/pest']; | ||||
|         } else { | ||||
|             $command = $this->option('parallel') ? ['vendor/brianium/paratest/bin/paratest'] : ['vendor/phpunit/phpunit/phpunit']; | ||||
| @@ -130,11 +179,37 @@ class TestCommand extends Command | ||||
|         return array_merge([PHP_BINARY], $command); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Gets the common arguments of PHPUnit and Pest. | ||||
|      * | ||||
|      * @return array | ||||
|      */ | ||||
|     protected function commonArguments() | ||||
|     { | ||||
|         $arguments = []; | ||||
|  | ||||
|         if ($this->option('coverage')) { | ||||
|             $arguments[] = '--coverage-php'; | ||||
|             $arguments[] = Coverage::getPath(); | ||||
|         } | ||||
|  | ||||
|         return $arguments; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Determines if Pest is being used. | ||||
|      * | ||||
|      * @return bool | ||||
|      */ | ||||
|     protected function usingPest() | ||||
|     { | ||||
|         return class_exists(\Pest\Laravel\PestServiceProvider::class); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Get the array of arguments for running PHPUnit. | ||||
|      * | ||||
|      * @param array $options | ||||
|      * | ||||
|      * @param  array  $options | ||||
|      * @return array | ||||
|      */ | ||||
|     protected function phpunitArguments($options) | ||||
| @@ -142,37 +217,45 @@ class TestCommand extends Command | ||||
|         $options = array_merge(['--printer=NunoMaduro\\Collision\\Adapters\\Phpunit\\Printer'], $options); | ||||
|  | ||||
|         $options = array_values(array_filter($options, function ($option) { | ||||
|             return !Str::startsWith($option, '--env='); | ||||
|             return ! Str::startsWith($option, '--env=') | ||||
|                 && $option != '-q' | ||||
|                 && $option != '--quiet' | ||||
|                 && $option != '--coverage' | ||||
|                 && ! Str::startsWith($option, '--min'); | ||||
|         })); | ||||
|  | ||||
|         if (!file_exists($file = base_path('phpunit.xml'))) { | ||||
|         if (! file_exists($file = base_path('phpunit.xml'))) { | ||||
|             $file = base_path('phpunit.xml.dist'); | ||||
|         } | ||||
|  | ||||
|         return array_merge(["--configuration=$file"], $options); | ||||
|         return array_merge($this->commonArguments(), ["--configuration=$file"], $options); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Get the array of arguments for running Paratest. | ||||
|      * | ||||
|      * @param array $options | ||||
|      * | ||||
|      * @param  array  $options | ||||
|      * @return array | ||||
|      */ | ||||
|     protected function paratestArguments($options) | ||||
|     { | ||||
|         $options = array_values(array_filter($options, function ($option) { | ||||
|             return !Str::startsWith($option, '--env=') | ||||
|                 && !Str::startsWith($option, '-p') | ||||
|                 && !Str::startsWith($option, '--parallel') | ||||
|                 && !Str::startsWith($option, '--recreate-databases'); | ||||
|             return ! Str::startsWith($option, '--env=') | ||||
|                 && $option != '--coverage' | ||||
|                 && $option != '-q' | ||||
|                 && $option != '--quiet' | ||||
|                 && ! Str::startsWith($option, '--min') | ||||
|                 && ! Str::startsWith($option, '-p') | ||||
|                 && ! Str::startsWith($option, '--parallel') | ||||
|                 && ! Str::startsWith($option, '--recreate-databases') | ||||
|                 && ! Str::startsWith($option, '--drop-databases'); | ||||
|         })); | ||||
|  | ||||
|         if (!file_exists($file = base_path('phpunit.xml'))) { | ||||
|         if (! file_exists($file = base_path('phpunit.xml'))) { | ||||
|             $file = base_path('phpunit.xml.dist'); | ||||
|         } | ||||
|  | ||||
|         return array_merge([ | ||||
|         return array_merge($this->commonArguments(), [ | ||||
|             "--configuration=$file", | ||||
|             "--runner=\Illuminate\Testing\ParallelRunner", | ||||
|         ], $options); | ||||
| @@ -196,8 +279,9 @@ class TestCommand extends Command | ||||
|     protected function paratestEnvironmentVariables() | ||||
|     { | ||||
|         return [ | ||||
|             'LARAVEL_PARALLEL_TESTING'                    => 1, | ||||
|             'LARAVEL_PARALLEL_TESTING' => 1, | ||||
|             'LARAVEL_PARALLEL_TESTING_RECREATE_DATABASES' => $this->option('recreate-databases'), | ||||
|             'LARAVEL_PARALLEL_TESTING_DROP_DATABASES' => $this->option('drop-databases'), | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
| @@ -208,7 +292,7 @@ class TestCommand extends Command | ||||
|      */ | ||||
|     protected function clearEnv() | ||||
|     { | ||||
|         if (!$this->option('env')) { | ||||
|         if (! $this->option('env')) { | ||||
|             $vars = self::getEnvironmentVariables( | ||||
|                 // @phpstan-ignore-next-line | ||||
|                 $this->laravel->environmentPath(), | ||||
| @@ -225,9 +309,8 @@ class TestCommand extends Command | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param string $path | ||||
|      * @param string $file | ||||
|      * | ||||
|      * @param  string  $path | ||||
|      * @param  string  $file | ||||
|      * @return array | ||||
|      */ | ||||
|     protected static function getEnvironmentVariables($path, $file) | ||||
| @@ -268,7 +351,7 @@ class TestCommand extends Command | ||||
|      */ | ||||
|     protected function installParallelDependencies() | ||||
|     { | ||||
|         $command = $this->findComposer() . ' require brianium/paratest --dev'; | ||||
|         $command = $this->findComposer().' require brianium/paratest --dev'; | ||||
|  | ||||
|         $process = Process::fromShellCommandline($command, null, null, null, null); | ||||
|  | ||||
| @@ -276,7 +359,7 @@ class TestCommand extends Command | ||||
|             try { | ||||
|                 $process->setTty(true); | ||||
|             } catch (RuntimeException $e) { | ||||
|                 $this->output->writeln('Warning: ' . $e->getMessage()); | ||||
|                 $this->output->writeln('Warning: '.$e->getMessage()); | ||||
|             } | ||||
|         } | ||||
|  | ||||
| @@ -298,10 +381,10 @@ class TestCommand extends Command | ||||
|      */ | ||||
|     protected function findComposer() | ||||
|     { | ||||
|         $composerPath = getcwd() . '/composer.phar'; | ||||
|         $composerPath = getcwd().'/composer.phar'; | ||||
|  | ||||
|         if (file_exists($composerPath)) { | ||||
|             return '"' . PHP_BINARY . '" ' . $composerPath; | ||||
|             return '"'.PHP_BINARY.'" '.$composerPath; | ||||
|         } | ||||
|  | ||||
|         return 'composer'; | ||||
|   | ||||
| @@ -34,7 +34,7 @@ final class ExceptionHandler implements ExceptionHandlerContract | ||||
|      */ | ||||
|     public function __construct(Container $container, ExceptionHandlerContract $appExceptionHandler) | ||||
|     { | ||||
|         $this->container           = $container; | ||||
|         $this->container = $container; | ||||
|         $this->appExceptionHandler = $appExceptionHandler; | ||||
|     } | ||||
|  | ||||
| @@ -62,8 +62,10 @@ final class ExceptionHandler implements ExceptionHandlerContract | ||||
|         if ($e instanceof SymfonyConsoleExceptionInterface) { | ||||
|             $this->appExceptionHandler->renderForConsole($output, $e); | ||||
|         } else { | ||||
|             $handler = $this->container->make(ProviderContract::class) | ||||
|                 ->register() | ||||
|             /** @var \NunoMaduro\Collision\Contracts\Provider $provider */ | ||||
|             $provider = $this->container->make(ProviderContract::class); | ||||
|  | ||||
|             $handler = $provider->register() | ||||
|                 ->getHandler() | ||||
|                 ->setOutput($output); | ||||
|  | ||||
|   | ||||
| @@ -4,8 +4,8 @@ declare(strict_types=1); | ||||
|  | ||||
| namespace NunoMaduro\Collision\Adapters\Laravel; | ||||
|  | ||||
| use Facade\IgnitionContracts\SolutionProviderRepository; | ||||
| use NunoMaduro\Collision\Contracts\SolutionsRepository; | ||||
| use Spatie\Ignition\Contracts\SolutionProviderRepository; | ||||
| use Throwable; | ||||
|  | ||||
| /** | ||||
| @@ -16,7 +16,7 @@ final class IgnitionSolutionsRepository implements SolutionsRepository | ||||
|     /** | ||||
|      * Holds an instance of ignition solutions provider repository. | ||||
|      * | ||||
|      * @var \Facade\IgnitionContracts\SolutionProviderRepository | ||||
|      * @var \Spatie\Ignition\Contracts\SolutionProviderRepository | ||||
|      */ | ||||
|     protected $solutionProviderRepository; | ||||
|  | ||||
|   | ||||
| @@ -25,15 +25,15 @@ final class ConfigureIO | ||||
| { | ||||
|     /** | ||||
|      * Configures both given input and output with | ||||
|      * options from the enviroment. | ||||
|      * options from the environment. | ||||
|      * | ||||
|      * @throws \ReflectionException | ||||
|      */ | ||||
|     public static function of(InputInterface $input, Output $output): void | ||||
|     { | ||||
|         $application = new Application(); | ||||
|         $reflector   = new ReflectionObject($application); | ||||
|         $method      = $reflector->getMethod('configureIO'); | ||||
|         $reflector = new ReflectionObject($application); | ||||
|         $method = $reflector->getMethod('configureIO'); | ||||
|         $method->setAccessible(true); | ||||
|         $method->invoke($application, $input, $output); | ||||
|     } | ||||
|   | ||||
| @@ -54,7 +54,7 @@ final class Printer implements \PHPUnit\TextUI\ResultPrinter | ||||
|     /** | ||||
|      * Creates a new instance of the listener. | ||||
|      * | ||||
|      * @param ConsoleOutput $output | ||||
|      * @param  ConsoleOutput  $output | ||||
|      * | ||||
|      * @throws \ReflectionException | ||||
|      */ | ||||
| @@ -69,7 +69,8 @@ final class Printer implements \PHPUnit\TextUI\ResultPrinter | ||||
|         ConfigureIO::of(new ArgvInput(), $output); | ||||
|  | ||||
|         $this->style = new Style($output); | ||||
|         $dummyTest   = new class() extends TestCase { | ||||
|         $dummyTest = new class() extends TestCase | ||||
|         { | ||||
|         }; | ||||
|  | ||||
|         $this->state = State::from($dummyTest); | ||||
| @@ -109,7 +110,7 @@ final class Printer implements \PHPUnit\TextUI\ResultPrinter | ||||
|         $reflector = new ReflectionObject($error); | ||||
|  | ||||
|         if ($reflector->hasProperty('message')) { | ||||
|             $message  = trim((string) preg_replace("/\r|\n/", "\n  ", $error->getMessage())); | ||||
|             $message = trim((string) preg_replace("/\r|\n/", "\n  ", $error->getMessage())); | ||||
|             $property = $reflector->getProperty('message'); | ||||
|             $property->setAccessible(true); | ||||
|             $property->setValue($error, $message); | ||||
| @@ -188,14 +189,14 @@ final class Printer implements \PHPUnit\TextUI\ResultPrinter | ||||
|     { | ||||
|         $testCase = $this->testCaseFromTest($testCase); | ||||
|  | ||||
|         if (!$this->state->existsInTestCase($testCase)) { | ||||
|         if (! $this->state->existsInTestCase($testCase)) { | ||||
|             $this->state->add(TestResult::fromTestCase($testCase, TestResult::PASS)); | ||||
|         } | ||||
|  | ||||
|         if ($testCase instanceof TestCase | ||||
|             && $testCase->getTestResultObject() instanceof \PHPUnit\Framework\TestResult | ||||
|             && !$testCase->getTestResultObject()->isStrictAboutOutputDuringTests() | ||||
|             && !$testCase->hasExpectationOnOutput()) { | ||||
|             && ! $testCase->getTestResultObject()->isStrictAboutOutputDuringTests() | ||||
|             && ! $testCase->hasExpectationOnOutput()) { | ||||
|             $this->style->write($testCase->getActualOutput()); | ||||
|         } | ||||
|     } | ||||
| @@ -217,7 +218,7 @@ final class Printer implements \PHPUnit\TextUI\ResultPrinter | ||||
|      */ | ||||
|     private function testCaseFromTest(Test $test): TestCase | ||||
|     { | ||||
|         if (!$test instanceof TestCase) { | ||||
|         if (! $test instanceof TestCase) { | ||||
|             throw new ShouldNotHappen(); | ||||
|         } | ||||
|  | ||||
|   | ||||
| @@ -75,7 +75,7 @@ final class State | ||||
|      */ | ||||
|     public function add(TestResult $test): void | ||||
|     { | ||||
|         $this->testCaseTests[]        = $test; | ||||
|         $this->testCaseTests[] = $test; | ||||
|         $this->toBePrintedCaseTests[] = $test; | ||||
|  | ||||
|         $this->suiteTests[] = $test; | ||||
|   | ||||
| @@ -29,7 +29,7 @@ final class Style | ||||
|      */ | ||||
|     public function __construct(ConsoleOutputInterface $output) | ||||
|     { | ||||
|         if (!$output instanceof ConsoleOutput) { | ||||
|         if (! $output instanceof ConsoleOutput) { | ||||
|             throw new ShouldNotHappen(); | ||||
|         } | ||||
|  | ||||
| @@ -58,7 +58,7 @@ final class Style | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         if (!$state->headerPrinted) { | ||||
|         if (! $state->headerPrinted) { | ||||
|             $this->output->writeln($this->titleLineFrom( | ||||
|                 $state->getTestCaseTitle() === 'FAIL' ? 'white' : 'black', | ||||
|                 $state->getTestCaseTitleColor(), | ||||
| @@ -92,12 +92,12 @@ final class Style | ||||
|             return $testResult->type === TestResult::FAIL; | ||||
|         }); | ||||
|  | ||||
|         if (!$onFailure) { | ||||
|         if (! $onFailure) { | ||||
|             $this->output->writeln(['', "  \e[2m---\e[22m", '']); | ||||
|         } | ||||
|  | ||||
|         array_map(function (TestResult $testResult) use ($onFailure) { | ||||
|             if (!$onFailure) { | ||||
|             if (! $onFailure) { | ||||
|                 $this->output->write(sprintf( | ||||
|                     '  <fg=red;options=bold>• %s </>> <fg=red;options=bold>%s</>', | ||||
|                     $testResult->testCaseName, | ||||
| @@ -105,7 +105,7 @@ final class Style | ||||
|                 )); | ||||
|             } | ||||
|  | ||||
|             if (!$testResult->throwable instanceof Throwable) { | ||||
|             if (! $testResult->throwable instanceof Throwable) { | ||||
|                 throw new ShouldNotHappen(); | ||||
|             } | ||||
|  | ||||
| @@ -121,7 +121,7 @@ final class Style | ||||
|         $types = [TestResult::FAIL, TestResult::WARN, TestResult::RISKY, TestResult::INCOMPLETE, TestResult::SKIPPED, TestResult::PASS]; | ||||
|         foreach ($types as $type) { | ||||
|             if (($countTests = $state->countTestsInTestSuiteBy($type)) !== 0) { | ||||
|                 $color   = TestResult::makeColor($type); | ||||
|                 $color = TestResult::makeColor($type); | ||||
|                 $tests[] = "<fg=$color;options=bold>$countTests $type</>"; | ||||
|             } | ||||
|         } | ||||
| @@ -131,7 +131,7 @@ final class Style | ||||
|             $tests[] = "\e[2m$pending pending\e[22m"; | ||||
|         } | ||||
|  | ||||
|         if (!empty($tests)) { | ||||
|         if (! empty($tests)) { | ||||
|             $this->output->write([ | ||||
|                 "\n", | ||||
|                 sprintf( | ||||
| @@ -144,12 +144,12 @@ final class Style | ||||
|         if ($timer !== null) { | ||||
|             $timeElapsed = number_format($timer->result(), 2, '.', ''); | ||||
|             $this->output->writeln([ | ||||
|                     '', | ||||
|                     sprintf( | ||||
|                         '  <fg=white;options=bold>Time:   </><fg=default>%ss</>', | ||||
|                         $timeElapsed | ||||
|                     ), | ||||
|                 ] | ||||
|                 '', | ||||
|                 sprintf( | ||||
|                     '  <fg=white;options=bold>Time:   </><fg=default>%ss</>', | ||||
|                     $timeElapsed | ||||
|                 ), | ||||
|             ] | ||||
|             ); | ||||
|         } | ||||
|  | ||||
| @@ -178,8 +178,11 @@ final class Style | ||||
|         } | ||||
|  | ||||
|         $writer->ignoreFilesIn([ | ||||
|             '/vendor\/bin\/pest/', | ||||
|             '/bin\/pest/', | ||||
|             '/vendor\/pestphp\/pest/', | ||||
|             '/vendor\/phpspec\/prophecy-phpunit/', | ||||
|             '/vendor\/phpspec\/prophecy/', | ||||
|             '/vendor\/phpunit\/phpunit\/src/', | ||||
|             '/vendor\/mockery\/mockery/', | ||||
|             '/vendor\/laravel\/dusk/', | ||||
| @@ -196,6 +199,7 @@ final class Style | ||||
|             '/bin\/phpunit/', | ||||
|             '/vendor\/coduo\/php-matcher\/src\/PHPUnit/', | ||||
|             '/vendor\/sulu\/sulu\/src\/Sulu\/Bundle\/TestBundle\/Testing/', | ||||
|             '/vendor\/webmozart\/assert/', | ||||
|         ]); | ||||
|  | ||||
|         if ($throwable instanceof ExceptionWrapper && $throwable->getOriginalException() !== null) { | ||||
| @@ -207,20 +211,20 @@ final class Style | ||||
|         $writer->write($inspector); | ||||
|  | ||||
|         if ($throwable instanceof ExpectationFailedException && $comparisionFailure = $throwable->getComparisonFailure()) { | ||||
|             $diff  = $comparisionFailure->getDiff(); | ||||
|             $diff = $comparisionFailure->getDiff(); | ||||
|             $lines = explode(PHP_EOL, $diff); | ||||
|             $diff  = ''; | ||||
|             $diff = ''; | ||||
|             foreach ($lines as $line) { | ||||
|                 if (0 === strpos($line, '-')) { | ||||
|                     $line = '<fg=red>' . $line . '</>'; | ||||
|                     $line = '<fg=red>'.$line.'</>'; | ||||
|                 } elseif (0 === strpos($line, '+')) { | ||||
|                     $line = '<fg=green>' . $line . '</>'; | ||||
|                     $line = '<fg=green>'.$line.'</>'; | ||||
|                 } | ||||
|  | ||||
|                 $diff .= $line . PHP_EOL; | ||||
|                 $diff .= $line.PHP_EOL; | ||||
|             } | ||||
|  | ||||
|             $diff  = trim((string) preg_replace("/\r|\n/", "\n  ", $diff)); | ||||
|             $diff = trim((string) preg_replace("/\r|\n/", "\n  ", $diff)); | ||||
|  | ||||
|             $this->output->write("  $diff"); | ||||
|         } | ||||
| @@ -247,7 +251,7 @@ final class Style | ||||
|      */ | ||||
|     private function testLineFrom(string $fg, string $icon, string $description, string $warning = null): string | ||||
|     { | ||||
|         if (!empty($warning)) { | ||||
|         if (! empty($warning)) { | ||||
|             $warning = sprintf( | ||||
|                 ' → %s', | ||||
|                 $warning | ||||
|   | ||||
| @@ -13,13 +13,19 @@ use Throwable; | ||||
|  */ | ||||
| final class TestResult | ||||
| { | ||||
|     public const FAIL       = 'failed'; | ||||
|     public const SKIPPED    = 'skipped'; | ||||
|     public const INCOMPLETE = 'incompleted'; | ||||
|     public const RISKY      = 'risked'; | ||||
|     public const WARN       = 'warnings'; | ||||
|     public const RUNS       = 'pending'; | ||||
|     public const PASS       = 'passed'; | ||||
|     public const FAIL = 'failed'; | ||||
|  | ||||
|     public const SKIPPED = 'skipped'; | ||||
|  | ||||
|     public const INCOMPLETE = 'incomplete'; | ||||
|  | ||||
|     public const RISKY = 'risky'; | ||||
|  | ||||
|     public const WARN = 'warnings'; | ||||
|  | ||||
|     public const RUNS = 'pending'; | ||||
|  | ||||
|     public const PASS = 'passed'; | ||||
|  | ||||
|     /** | ||||
|      * @readonly | ||||
| @@ -76,11 +82,11 @@ final class TestResult | ||||
|     private function __construct(string $testCaseName, string $description, string $type, string $icon, string $color, Throwable $throwable = null) | ||||
|     { | ||||
|         $this->testCaseName = $testCaseName; | ||||
|         $this->description  = $description; | ||||
|         $this->type         = $type; | ||||
|         $this->icon         = $icon; | ||||
|         $this->color        = $color; | ||||
|         $this->throwable    = $throwable; | ||||
|         $this->description = $description; | ||||
|         $this->type = $type; | ||||
|         $this->icon = $icon; | ||||
|         $this->color = $color; | ||||
|         $this->throwable = $throwable; | ||||
|  | ||||
|         $asWarning = $this->type === TestResult::WARN | ||||
|              || $this->type === TestResult::RISKY | ||||
| @@ -88,7 +94,7 @@ final class TestResult | ||||
|              || $this->type === TestResult::INCOMPLETE; | ||||
|  | ||||
|         if ($throwable instanceof Throwable && $asWarning) { | ||||
|             $this->warning     = trim((string) preg_replace("/\r|\n/", ' ', $throwable->getMessage())); | ||||
|             $this->warning = trim((string) preg_replace("/\r|\n/", ' ', $throwable->getMessage())); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -25,16 +25,16 @@ final class ArgumentFormatter implements ArgumentFormatterContract | ||||
|         foreach ($arguments as $argument) { | ||||
|             switch (true) { | ||||
|                 case is_string($argument): | ||||
|                     $result[] = '"' . (mb_strlen($argument) > self::MAX_STRING_LENGTH ? mb_substr($argument, 0, self::MAX_STRING_LENGTH) . '...' : $argument) . '"'; | ||||
|                     $result[] = '"'.(mb_strlen($argument) > self::MAX_STRING_LENGTH ? mb_substr($argument, 0, self::MAX_STRING_LENGTH).'...' : $argument).'"'; | ||||
|                     break; | ||||
|                 case is_array($argument): | ||||
|                     $associative = array_keys($argument) !== range(0, count($argument) - 1); | ||||
|                     if ($recursive && $associative && count($argument) <= 5) { | ||||
|                         $result[] = '[' . $this->format($argument, false) . ']'; | ||||
|                         $result[] = '['.$this->format($argument, false).']'; | ||||
|                     } | ||||
|                     break; | ||||
|                 case is_object($argument): | ||||
|                     $class    = get_class($argument); | ||||
|                     $class = get_class($argument); | ||||
|                     $result[] = "Object($class)"; | ||||
|                     break; | ||||
|             } | ||||
|   | ||||
							
								
								
									
										115
									
								
								vendor/nunomaduro/collision/src/ConsoleColor.php
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										115
									
								
								vendor/nunomaduro/collision/src/ConsoleColor.php
									
									
									
									
										vendored
									
									
								
							| @@ -13,6 +13,7 @@ use NunoMaduro\Collision\Exceptions\ShouldNotHappen; | ||||
| final class ConsoleColor | ||||
| { | ||||
|     public const FOREGROUND = 38; | ||||
|  | ||||
|     public const BACKGROUND = 48; | ||||
|  | ||||
|     public const COLOR256_REGEXP = '~^(bg_)?color_(\d{1,3})$~'; | ||||
| @@ -27,52 +28,52 @@ final class ConsoleColor | ||||
|  | ||||
|     /** @var array */ | ||||
|     private const STYLES = [ | ||||
|         'none'      => null, | ||||
|         'bold'      => '1', | ||||
|         'dark'      => '2', | ||||
|         'italic'    => '3', | ||||
|         'none' => null, | ||||
|         'bold' => '1', | ||||
|         'dark' => '2', | ||||
|         'italic' => '3', | ||||
|         'underline' => '4', | ||||
|         'blink'     => '5', | ||||
|         'reverse'   => '7', | ||||
|         'blink' => '5', | ||||
|         'reverse' => '7', | ||||
|         'concealed' => '8', | ||||
|  | ||||
|         'default'    => '39', | ||||
|         'black'      => '30', | ||||
|         'red'        => '31', | ||||
|         'green'      => '32', | ||||
|         'yellow'     => '33', | ||||
|         'blue'       => '34', | ||||
|         'magenta'    => '35', | ||||
|         'cyan'       => '36', | ||||
|         'default' => '39', | ||||
|         'black' => '30', | ||||
|         'red' => '31', | ||||
|         'green' => '32', | ||||
|         'yellow' => '33', | ||||
|         'blue' => '34', | ||||
|         'magenta' => '35', | ||||
|         'cyan' => '36', | ||||
|         'light_gray' => '37', | ||||
|  | ||||
|         'dark_gray'     => '90', | ||||
|         'light_red'     => '91', | ||||
|         'light_green'   => '92', | ||||
|         'light_yellow'  => '93', | ||||
|         'light_blue'    => '94', | ||||
|         'dark_gray' => '90', | ||||
|         'light_red' => '91', | ||||
|         'light_green' => '92', | ||||
|         'light_yellow' => '93', | ||||
|         'light_blue' => '94', | ||||
|         'light_magenta' => '95', | ||||
|         'light_cyan'    => '96', | ||||
|         'white'         => '97', | ||||
|         'light_cyan' => '96', | ||||
|         'white' => '97', | ||||
|  | ||||
|         'bg_default'    => '49', | ||||
|         'bg_black'      => '40', | ||||
|         'bg_red'        => '41', | ||||
|         'bg_green'      => '42', | ||||
|         'bg_yellow'     => '43', | ||||
|         'bg_blue'       => '44', | ||||
|         'bg_magenta'    => '45', | ||||
|         'bg_cyan'       => '46', | ||||
|         'bg_default' => '49', | ||||
|         'bg_black' => '40', | ||||
|         'bg_red' => '41', | ||||
|         'bg_green' => '42', | ||||
|         'bg_yellow' => '43', | ||||
|         'bg_blue' => '44', | ||||
|         'bg_magenta' => '45', | ||||
|         'bg_cyan' => '46', | ||||
|         'bg_light_gray' => '47', | ||||
|  | ||||
|         'bg_dark_gray'     => '100', | ||||
|         'bg_light_red'     => '101', | ||||
|         'bg_light_green'   => '102', | ||||
|         'bg_light_yellow'  => '103', | ||||
|         'bg_light_blue'    => '104', | ||||
|         'bg_dark_gray' => '100', | ||||
|         'bg_light_red' => '101', | ||||
|         'bg_light_green' => '102', | ||||
|         'bg_light_yellow' => '103', | ||||
|         'bg_light_blue' => '104', | ||||
|         'bg_light_magenta' => '105', | ||||
|         'bg_light_cyan'    => '106', | ||||
|         'bg_white'         => '107', | ||||
|         'bg_light_cyan' => '106', | ||||
|         'bg_white' => '107', | ||||
|     ]; | ||||
|  | ||||
|     /** @var array */ | ||||
| @@ -84,9 +85,8 @@ final class ConsoleColor | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param string|array $style | ||||
|      * @param string       $text | ||||
|      * | ||||
|      * @param  string|array  $style | ||||
|      * @param  string  $text | ||||
|      * @return string | ||||
|      * | ||||
|      * @throws InvalidStyleException | ||||
| @@ -94,14 +94,14 @@ final class ConsoleColor | ||||
|      */ | ||||
|     public function apply($style, $text) | ||||
|     { | ||||
|         if (!$this->isStyleForced() && !$this->isSupported()) { | ||||
|         if (! $this->isStyleForced() && ! $this->isSupported()) { | ||||
|             return $text; | ||||
|         } | ||||
|  | ||||
|         if (is_string($style)) { | ||||
|             $style = [$style]; | ||||
|         } | ||||
|         if (!is_array($style)) { | ||||
|         if (! is_array($style)) { | ||||
|             throw new \InvalidArgumentException('Style must be string or array.'); | ||||
|         } | ||||
|  | ||||
| @@ -125,11 +125,11 @@ final class ConsoleColor | ||||
|             return $text; | ||||
|         } | ||||
|  | ||||
|         return $this->escSequence(implode(';', $sequences)) . $text . $this->escSequence(self::RESET_STYLE); | ||||
|         return $this->escSequence(implode(';', $sequences)).$text.$this->escSequence(self::RESET_STYLE); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param bool $forceStyle | ||||
|      * @param  bool  $forceStyle | ||||
|      */ | ||||
|     public function setForceStyle($forceStyle) | ||||
|     { | ||||
| @@ -153,20 +153,20 @@ final class ConsoleColor | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param string       $name | ||||
|      * @param array|string $styles | ||||
|      * @param  string  $name | ||||
|      * @param  array|string  $styles | ||||
|      */ | ||||
|     public function addTheme($name, $styles) | ||||
|     { | ||||
|         if (is_string($styles)) { | ||||
|             $styles = [$styles]; | ||||
|         } | ||||
|         if (!is_array($styles)) { | ||||
|         if (! is_array($styles)) { | ||||
|             throw new \InvalidArgumentException('Style must be string or array.'); | ||||
|         } | ||||
|  | ||||
|         foreach ($styles as $style) { | ||||
|             if (!$this->isValidStyle($style)) { | ||||
|             if (! $this->isValidStyle($style)) { | ||||
|                 throw new InvalidStyleException($style); | ||||
|             } | ||||
|         } | ||||
| @@ -183,8 +183,7 @@ final class ConsoleColor | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param string $name | ||||
|      * | ||||
|      * @param  string  $name | ||||
|      * @return bool | ||||
|      */ | ||||
|     public function hasTheme($name) | ||||
| @@ -193,7 +192,7 @@ final class ConsoleColor | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param string $name | ||||
|      * @param  string  $name | ||||
|      */ | ||||
|     public function removeTheme($name) | ||||
|     { | ||||
| @@ -238,8 +237,7 @@ final class ConsoleColor | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param string $name | ||||
|      * | ||||
|      * @param  string  $name | ||||
|      * @return string[] | ||||
|      */ | ||||
|     private function themeSequence($name) | ||||
| @@ -253,8 +251,7 @@ final class ConsoleColor | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param string $style | ||||
|      * | ||||
|      * @param  string  $style | ||||
|      * @return string | ||||
|      */ | ||||
|     private function styleSequence($style) | ||||
| @@ -263,21 +260,20 @@ final class ConsoleColor | ||||
|             return self::STYLES[$style]; | ||||
|         } | ||||
|  | ||||
|         if (!$this->are256ColorsSupported()) { | ||||
|         if (! $this->are256ColorsSupported()) { | ||||
|             return null; | ||||
|         } | ||||
|  | ||||
|         preg_match(self::COLOR256_REGEXP, $style, $matches); | ||||
|  | ||||
|         $type  = $matches[1] === 'bg_' ? self::BACKGROUND : self::FOREGROUND; | ||||
|         $type = $matches[1] === 'bg_' ? self::BACKGROUND : self::FOREGROUND; | ||||
|         $value = $matches[2]; | ||||
|  | ||||
|         return "$type;5;$value"; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param string $style | ||||
|      * | ||||
|      * @param  string  $style | ||||
|      * @return bool | ||||
|      */ | ||||
|     private function isValidStyle($style) | ||||
| @@ -286,8 +282,7 @@ final class ConsoleColor | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param string|int $value | ||||
|      * | ||||
|      * @param  string|int  $value | ||||
|      * @return string | ||||
|      */ | ||||
|     private function escSequence($value) | ||||
|   | ||||
| @@ -4,7 +4,7 @@ declare(strict_types=1); | ||||
|  | ||||
| namespace NunoMaduro\Collision\Contracts; | ||||
|  | ||||
| use Facade\IgnitionContracts\Solution; | ||||
| use Spatie\Ignition\Contracts\Solution; | ||||
| use Throwable; | ||||
|  | ||||
| /** | ||||
|   | ||||
| @@ -25,8 +25,7 @@ interface Writer | ||||
|      * Ignores traces where the file string matches one | ||||
|      * of the provided regex expressions. | ||||
|      * | ||||
|      * @param string[] $ignore the regex expressions | ||||
|      * | ||||
|      * @param  string[]  $ignore the regex expressions | ||||
|      * @return \NunoMaduro\Collision\Contracts\Writer | ||||
|      */ | ||||
|     public function ignoreFilesIn(array $ignore): Writer; | ||||
|   | ||||
							
								
								
									
										201
									
								
								vendor/nunomaduro/collision/src/Coverage.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										201
									
								
								vendor/nunomaduro/collision/src/Coverage.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,201 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| namespace NunoMaduro\Collision; | ||||
|  | ||||
| use SebastianBergmann\CodeCoverage\CodeCoverage; | ||||
| use SebastianBergmann\CodeCoverage\Node\Directory; | ||||
| use SebastianBergmann\CodeCoverage\Node\File; | ||||
| use SebastianBergmann\Environment\Runtime; | ||||
| use Symfony\Component\Console\Output\OutputInterface; | ||||
| use Symfony\Component\Console\Terminal; | ||||
|  | ||||
| /** | ||||
|  * @internal | ||||
|  */ | ||||
| final class Coverage | ||||
| { | ||||
|     /** | ||||
|      * Returns the coverage path. | ||||
|      */ | ||||
|     public static function getPath(): string | ||||
|     { | ||||
|         return implode(DIRECTORY_SEPARATOR, [ | ||||
|             dirname(__DIR__), | ||||
|             '.temp', | ||||
|             'coverage', | ||||
|         ]); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Runs true there is any code coverage driver available. | ||||
|      */ | ||||
|     public static function isAvailable(): bool | ||||
|     { | ||||
|         if (! (new Runtime())->canCollectCodeCoverage()) { | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         if (static::usingXdebug()) { | ||||
|             $mode = getenv('XDEBUG_MODE') ?: ini_get('xdebug.mode'); | ||||
|  | ||||
|             return $mode && in_array('coverage', explode(',', $mode), true); | ||||
|         } | ||||
|  | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * If the user is using Xdebug. | ||||
|      */ | ||||
|     public static function usingXdebug(): bool | ||||
|     { | ||||
|         return (new Runtime())->hasXdebug(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Reports the code coverage report to the | ||||
|      * console and returns the result in float. | ||||
|      */ | ||||
|     public static function report(OutputInterface $output): float | ||||
|     { | ||||
|         if (! file_exists($reportPath = self::getPath())) { | ||||
|             if (self::usingXdebug()) { | ||||
|                 $output->writeln( | ||||
|                     "  <fg=black;bg=yellow;options=bold> WARN </> Unable to get coverage using Xdebug. Did you set <href=https://xdebug.org/docs/code_coverage#mode>Xdebug's coverage mode</>?</>", | ||||
|                 ); | ||||
|  | ||||
|                 return 0.0; | ||||
|             } | ||||
|  | ||||
|             $output->writeln( | ||||
|                 '  <fg=black;bg=yellow;options=bold> WARN </> No coverage driver detected.</>', | ||||
|             ); | ||||
|  | ||||
|             return 0.0; | ||||
|         } | ||||
|  | ||||
|         /** @var CodeCoverage $codeCoverage */ | ||||
|         $codeCoverage = require $reportPath; | ||||
|         unlink($reportPath); | ||||
|  | ||||
|         $totalCoverage = $codeCoverage->getReport()->percentageOfExecutedLines(); | ||||
|  | ||||
|         $totalWidth = (new Terminal())->getWidth(); | ||||
|  | ||||
|         $dottedLineLength = $totalWidth; | ||||
|  | ||||
|         /** @var Directory<File|Directory> $report */ | ||||
|         $report = $codeCoverage->getReport(); | ||||
|  | ||||
|         foreach ($report->getIterator() as $file) { | ||||
|             if (! $file instanceof File) { | ||||
|                 continue; | ||||
|             } | ||||
|             $dirname = dirname($file->id()); | ||||
|             $basename = basename($file->id(), '.php'); | ||||
|  | ||||
|             $name = $dirname === '.' ? $basename : implode(DIRECTORY_SEPARATOR, [ | ||||
|                 $dirname, | ||||
|                 $basename, | ||||
|             ]); | ||||
|             $rawName = $dirname === '.' ? $basename : implode(DIRECTORY_SEPARATOR, [ | ||||
|                 $dirname, | ||||
|                 $basename, | ||||
|             ]); | ||||
|  | ||||
|             $linesExecutedTakenSize = 0; | ||||
|  | ||||
|             if ($file->percentageOfExecutedLines()->asString() != '0.00%') { | ||||
|                 $linesExecutedTakenSize = strlen($uncoveredLines = trim(implode(', ', self::getMissingCoverage($file)))) + 1; | ||||
|                 $name .= sprintf(' <fg=red>%s</>', $uncoveredLines); | ||||
|             } | ||||
|  | ||||
|             $percentage = $file->numberOfExecutableLines() === 0 | ||||
|                 ? '100.0' | ||||
|                 : number_format($file->percentageOfExecutedLines()->asFloat(), 1, '.', ''); | ||||
|  | ||||
|             $takenSize = strlen($rawName.$percentage) + 8 + $linesExecutedTakenSize; // adding 3 space and percent sign | ||||
|  | ||||
|             $percentage = sprintf( | ||||
|                 '<fg=%s%s>%s</>', | ||||
|                 $percentage === '100.0' ? 'green' : ($percentage === '0.0' ? 'red' : 'yellow'), | ||||
|                 $percentage === '100.0' ? ';options=bold' : '', | ||||
|                 $percentage | ||||
|             ); | ||||
|  | ||||
|             $output->writeln(sprintf( | ||||
|                 '  <fg=white>%s</> <fg=#6C7280>%s</> %s <fg=#6C7280>%%</>', | ||||
|                 $name, | ||||
|                 str_repeat('.', max($dottedLineLength - $takenSize, 1)), | ||||
|                 $percentage | ||||
|             )); | ||||
|         } | ||||
|  | ||||
|         $output->writeln(''); | ||||
|  | ||||
|         $rawName = 'Total Coverage'; | ||||
|  | ||||
|         $takenSize = strlen($rawName.$totalCoverage->asString()) + 6; | ||||
|  | ||||
|         $output->writeln(sprintf( | ||||
|             '  <fg=white;options=bold>%s</> <fg=#6C7280>%s</> %s <fg=#6C7280>%%</>', | ||||
|             $rawName, | ||||
|             str_repeat('.', max($dottedLineLength - $takenSize, 1)), | ||||
|             number_format($totalCoverage->asFloat(), 1, '.', '') | ||||
|         )); | ||||
|  | ||||
|         return $totalCoverage->asFloat(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Generates an array of missing coverage on the following format:. | ||||
|      * | ||||
|      * ``` | ||||
|      * ['11', '20..25', '50', '60..80']; | ||||
|      * ``` | ||||
|      * | ||||
|      * @param  File  $file | ||||
|      * @return array<int, string> | ||||
|      */ | ||||
|     public static function getMissingCoverage($file): array | ||||
|     { | ||||
|         $shouldBeNewLine = true; | ||||
|  | ||||
|         $eachLine = function (array $array, array $tests, int $line) use (&$shouldBeNewLine): array { | ||||
|             if (count($tests) > 0) { | ||||
|                 $shouldBeNewLine = true; | ||||
|  | ||||
|                 return $array; | ||||
|             } | ||||
|  | ||||
|             if ($shouldBeNewLine) { | ||||
|                 $array[] = (string) $line; | ||||
|                 $shouldBeNewLine = false; | ||||
|  | ||||
|                 return $array; | ||||
|             } | ||||
|  | ||||
|             $lastKey = count($array) - 1; | ||||
|  | ||||
|             if (array_key_exists($lastKey, $array) && str_contains($array[$lastKey], '..')) { | ||||
|                 [$from] = explode('..', $array[$lastKey]); | ||||
|                 $array[$lastKey] = $line > $from ? sprintf('%s..%s', $from, $line) : sprintf('%s..%s', $line, $from); | ||||
|  | ||||
|                 return $array; | ||||
|             } | ||||
|  | ||||
|             $array[$lastKey] = sprintf('%s..%s', $array[$lastKey], $line); | ||||
|  | ||||
|             return $array; | ||||
|         }; | ||||
|  | ||||
|         $array = []; | ||||
|         foreach (array_filter($file->lineCoverageData(), 'is_array') as $line => $tests) { | ||||
|             $array = $eachLine($array, $tests, $line); | ||||
|         } | ||||
|  | ||||
|         return $array; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										111
									
								
								vendor/nunomaduro/collision/src/Highlighter.php
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										111
									
								
								vendor/nunomaduro/collision/src/Highlighter.php
									
									
									
									
										vendored
									
									
								
							| @@ -11,58 +11,75 @@ use NunoMaduro\Collision\Contracts\Highlighter as HighlighterContract; | ||||
|  */ | ||||
| final class Highlighter implements HighlighterContract | ||||
| { | ||||
|     public const TOKEN_DEFAULT    = 'token_default'; | ||||
|     public const TOKEN_COMMENT    = 'token_comment'; | ||||
|     public const TOKEN_STRING     = 'token_string'; | ||||
|     public const TOKEN_HTML       = 'token_html'; | ||||
|     public const TOKEN_KEYWORD    = 'token_keyword'; | ||||
|     public const ACTUAL_LINE_MARK = 'actual_line_mark'; | ||||
|     public const LINE_NUMBER      = 'line_number'; | ||||
|     public const TOKEN_DEFAULT = 'token_default'; | ||||
|  | ||||
|     public const TOKEN_COMMENT = 'token_comment'; | ||||
|  | ||||
|     public const TOKEN_STRING = 'token_string'; | ||||
|  | ||||
|     public const TOKEN_HTML = 'token_html'; | ||||
|  | ||||
|     public const TOKEN_KEYWORD = 'token_keyword'; | ||||
|  | ||||
|     public const ACTUAL_LINE_MARK = 'actual_line_mark'; | ||||
|  | ||||
|     public const LINE_NUMBER = 'line_number'; | ||||
|  | ||||
|     private const ARROW_SYMBOL = '>'; | ||||
|  | ||||
|     private const DELIMITER = '|'; | ||||
|  | ||||
|     private const ARROW_SYMBOL_UTF8 = '➜'; | ||||
|  | ||||
|     private const DELIMITER_UTF8 = '▕'; // '▶'; | ||||
|  | ||||
|     private const ARROW_SYMBOL        = '>'; | ||||
|     private const DELIMITER           = '|'; | ||||
|     private const ARROW_SYMBOL_UTF8   = '➜'; | ||||
|     private const DELIMITER_UTF8      = '▕'; // '▶'; | ||||
|     private const LINE_NUMBER_DIVIDER = 'line_divider'; | ||||
|     private const MARKED_LINE_NUMBER  = 'marked_line'; | ||||
|     private const WIDTH               = 3; | ||||
|  | ||||
|     private const MARKED_LINE_NUMBER = 'marked_line'; | ||||
|  | ||||
|     private const WIDTH = 3; | ||||
|  | ||||
|     /** | ||||
|      * Holds the theme. | ||||
|      * | ||||
|      * @var array | ||||
|      */ | ||||
|     private const THEME = [ | ||||
|         self::TOKEN_STRING  => ['light_gray'], | ||||
|         self::TOKEN_STRING => ['light_gray'], | ||||
|         self::TOKEN_COMMENT => ['dark_gray', 'italic'], | ||||
|         self::TOKEN_KEYWORD => ['magenta', 'bold'], | ||||
|         self::TOKEN_DEFAULT => ['default', 'bold'], | ||||
|         self::TOKEN_HTML    => ['blue', 'bold'], | ||||
|         self::TOKEN_HTML => ['blue', 'bold'], | ||||
|  | ||||
|         self::ACTUAL_LINE_MARK    => ['red', 'bold'], | ||||
|         self::LINE_NUMBER         => ['dark_gray'], | ||||
|         self::MARKED_LINE_NUMBER  => ['italic', 'bold'], | ||||
|         self::ACTUAL_LINE_MARK => ['red', 'bold'], | ||||
|         self::LINE_NUMBER => ['dark_gray'], | ||||
|         self::MARKED_LINE_NUMBER => ['italic', 'bold'], | ||||
|         self::LINE_NUMBER_DIVIDER => ['dark_gray'], | ||||
|     ]; | ||||
|  | ||||
|     /** @var ConsoleColor */ | ||||
|     private $color; | ||||
|  | ||||
|     /** @var array */ | ||||
|     private const DEFAULT_THEME = [ | ||||
|         self::TOKEN_STRING  => 'red', | ||||
|         self::TOKEN_STRING => 'red', | ||||
|         self::TOKEN_COMMENT => 'yellow', | ||||
|         self::TOKEN_KEYWORD => 'green', | ||||
|         self::TOKEN_DEFAULT => 'default', | ||||
|         self::TOKEN_HTML    => 'cyan', | ||||
|         self::TOKEN_HTML => 'cyan', | ||||
|  | ||||
|         self::ACTUAL_LINE_MARK    => 'dark_gray', | ||||
|         self::LINE_NUMBER         => 'dark_gray', | ||||
|         self::MARKED_LINE_NUMBER  => 'dark_gray', | ||||
|         self::ACTUAL_LINE_MARK => 'dark_gray', | ||||
|         self::LINE_NUMBER => 'dark_gray', | ||||
|         self::MARKED_LINE_NUMBER => 'dark_gray', | ||||
|         self::LINE_NUMBER_DIVIDER => 'dark_gray', | ||||
|     ]; | ||||
|  | ||||
|     /** @var string */ | ||||
|     private $delimiter = self::DELIMITER_UTF8; | ||||
|  | ||||
|     /** @var string */ | ||||
|     private $arrow = self::ARROW_SYMBOL_UTF8; | ||||
|  | ||||
|     /** | ||||
|      * @var string | ||||
|      */ | ||||
| @@ -76,7 +93,7 @@ final class Highlighter implements HighlighterContract | ||||
|         $this->color = $color ?: new ConsoleColor(); | ||||
|  | ||||
|         foreach (self::DEFAULT_THEME as $name => $styles) { | ||||
|             if (!$this->color->hasTheme($name)) { | ||||
|             if (! $this->color->hasTheme($name)) { | ||||
|                 $this->color->addTheme($name, $styles); | ||||
|             } | ||||
|         } | ||||
| @@ -84,9 +101,9 @@ final class Highlighter implements HighlighterContract | ||||
|         foreach (self::THEME as $name => $styles) { | ||||
|             $this->color->addTheme($name, $styles); | ||||
|         } | ||||
|         if (!$UTF8) { | ||||
|         if (! $UTF8) { | ||||
|             $this->delimiter = self::DELIMITER; | ||||
|             $this->arrow     = self::ARROW_SYMBOL; | ||||
|             $this->arrow = self::ARROW_SYMBOL; | ||||
|         } | ||||
|         $this->delimiter .= ' '; | ||||
|     } | ||||
| @@ -100,18 +117,18 @@ final class Highlighter implements HighlighterContract | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param string $source | ||||
|      * @param int    $lineNumber | ||||
|      * @param int    $linesBefore | ||||
|      * @param int    $linesAfter | ||||
|      * @param  string  $source | ||||
|      * @param  int  $lineNumber | ||||
|      * @param  int  $linesBefore | ||||
|      * @param  int  $linesAfter | ||||
|      */ | ||||
|     public function getCodeSnippet($source, $lineNumber, $linesBefore = 2, $linesAfter = 2): string | ||||
|     { | ||||
|         $tokenLines = $this->getHighlightedLines($source); | ||||
|  | ||||
|         $offset     = $lineNumber - $linesBefore - 1; | ||||
|         $offset     = max($offset, 0); | ||||
|         $length     = $linesAfter + $linesBefore + 1; | ||||
|         $offset = $lineNumber - $linesBefore - 1; | ||||
|         $offset = max($offset, 0); | ||||
|         $length = $linesAfter + $linesBefore + 1; | ||||
|         $tokenLines = array_slice($tokenLines, $offset, $length, $preserveKeys = true); | ||||
|  | ||||
|         $lines = $this->colorLines($tokenLines); | ||||
| @@ -120,7 +137,7 @@ final class Highlighter implements HighlighterContract | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param string $source | ||||
|      * @param  string  $source | ||||
|      */ | ||||
|     private function getHighlightedLines($source): array | ||||
|     { | ||||
| @@ -131,15 +148,15 @@ final class Highlighter implements HighlighterContract | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param string $source | ||||
|      * @param  string  $source | ||||
|      */ | ||||
|     private function tokenize($source): array | ||||
|     { | ||||
|         $tokens = token_get_all($source); | ||||
|  | ||||
|         $output      = []; | ||||
|         $output = []; | ||||
|         $currentType = null; | ||||
|         $buffer      = ''; | ||||
|         $buffer = ''; | ||||
|  | ||||
|         foreach ($tokens as $token) { | ||||
|             if (is_array($token)) { | ||||
| @@ -192,8 +209,8 @@ final class Highlighter implements HighlighterContract | ||||
|             } | ||||
|  | ||||
|             if ($currentType !== $newType) { | ||||
|                 $output[]    = [$currentType, $buffer]; | ||||
|                 $buffer      = ''; | ||||
|                 $output[] = [$currentType, $buffer]; | ||||
|                 $buffer = ''; | ||||
|                 $currentType = $newType; | ||||
|             } | ||||
|  | ||||
| @@ -216,7 +233,7 @@ final class Highlighter implements HighlighterContract | ||||
|             foreach (explode("\n", $token[1]) as $count => $tokenLine) { | ||||
|                 if ($count > 0) { | ||||
|                     $lines[] = $line; | ||||
|                     $line    = []; | ||||
|                     $line = []; | ||||
|                 } | ||||
|  | ||||
|                 if ($tokenLine === '') { | ||||
| @@ -252,14 +269,14 @@ final class Highlighter implements HighlighterContract | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param int|null $markLine | ||||
|      * @param  int|null  $markLine | ||||
|      */ | ||||
|     private function lineNumbers(array $lines, $markLine = null): string | ||||
|     { | ||||
|         $lineStrlen = strlen((string) (array_key_last($lines) + 1)); | ||||
|         $lineStrlen = $lineStrlen < self::WIDTH ? self::WIDTH : $lineStrlen; | ||||
|         $snippet    = ''; | ||||
|         $mark       = '  ' . $this->arrow . ' '; | ||||
|         $snippet = ''; | ||||
|         $mark = '  '.$this->arrow.' '; | ||||
|         foreach ($lines as $i => $line) { | ||||
|             $coloredLineNumber = $this->coloredLineNumber(self::LINE_NUMBER, $i, $lineStrlen); | ||||
|  | ||||
| @@ -281,16 +298,16 @@ final class Highlighter implements HighlighterContract | ||||
|             $snippet .= | ||||
|                 $this->color->apply(self::LINE_NUMBER_DIVIDER, $this->delimiter); | ||||
|  | ||||
|             $snippet .= $line . PHP_EOL; | ||||
|             $snippet .= $line.PHP_EOL; | ||||
|         } | ||||
|  | ||||
|         return $snippet; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param string $style | ||||
|      * @param int    $i | ||||
|      * @param int    $lineStrlen | ||||
|      * @param  string  $style | ||||
|      * @param  int  $i | ||||
|      * @param  int  $lineStrlen | ||||
|      */ | ||||
|     private function coloredLineNumber($style, $i, $lineStrlen): string | ||||
|     { | ||||
|   | ||||
							
								
								
									
										2
									
								
								vendor/nunomaduro/collision/src/Provider.php
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/nunomaduro/collision/src/Provider.php
									
									
									
									
										vendored
									
									
								
							| @@ -35,7 +35,7 @@ final class Provider implements ProviderContract | ||||
|      */ | ||||
|     public function __construct(RunInterface $run = null, HandlerContract $handler = null) | ||||
|     { | ||||
|         $this->run     = $run ?: new Run(); | ||||
|         $this->run = $run ?: new Run(); | ||||
|         $this->handler = $handler ?: new Handler(); | ||||
|     } | ||||
|  | ||||
|   | ||||
							
								
								
									
										45
									
								
								vendor/nunomaduro/collision/src/Writer.php
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										45
									
								
								vendor/nunomaduro/collision/src/Writer.php
									
									
									
									
										vendored
									
									
								
							| @@ -95,9 +95,9 @@ final class Writer implements WriterContract | ||||
|         HighlighterContract $highlighter = null | ||||
|     ) { | ||||
|         $this->solutionsRepository = $solutionsRepository ?: new NullSolutionsRepository(); | ||||
|         $this->output              = $output ?: new ConsoleOutput(); | ||||
|         $this->argumentFormatter   = $argumentFormatter ?: new ArgumentFormatter(); | ||||
|         $this->highlighter         = $highlighter ?: new Highlighter(); | ||||
|         $this->output = $output ?: new ConsoleOutput(); | ||||
|         $this->argumentFormatter = $argumentFormatter ?: new ArgumentFormatter(); | ||||
|         $this->highlighter = $highlighter ?: new Highlighter(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
| @@ -115,16 +115,16 @@ final class Writer implements WriterContract | ||||
|  | ||||
|         if ($this->showEditor | ||||
|             && $editorFrame !== null | ||||
|             && !$exception instanceof RenderlessEditor | ||||
|             && ! $exception instanceof RenderlessEditor | ||||
|         ) { | ||||
|             $this->renderEditor($editorFrame); | ||||
|         } | ||||
|  | ||||
|         $this->renderSolution($inspector); | ||||
|  | ||||
|         if ($this->showTrace && !empty($frames) && !$exception instanceof RenderlessTrace) { | ||||
|         if ($this->showTrace && ! empty($frames) && ! $exception instanceof RenderlessTrace) { | ||||
|             $this->renderTrace($frames); | ||||
|         } elseif (!$exception instanceof RenderlessEditor) { | ||||
|         } elseif (! $exception instanceof RenderlessEditor) { | ||||
|             $this->output->writeln(''); | ||||
|         } | ||||
|     } | ||||
| @@ -222,8 +222,8 @@ final class Writer implements WriterContract | ||||
|     protected function renderTitleAndDescription(Inspector $inspector): WriterContract | ||||
|     { | ||||
|         $exception = $inspector->getException(); | ||||
|         $message   = rtrim($exception->getMessage()); | ||||
|         $class     = $inspector->getExceptionName(); | ||||
|         $message = rtrim($exception->getMessage()); | ||||
|         $class = $inspector->getExceptionName(); | ||||
|  | ||||
|         if ($this->showTitle) { | ||||
|             $this->render("<bg=red;options=bold> $class </>"); | ||||
| @@ -244,19 +244,19 @@ final class Writer implements WriterContract | ||||
|         $solutions = $this->solutionsRepository->getFromThrowable($throwable); | ||||
|  | ||||
|         foreach ($solutions as $solution) { | ||||
|             /** @var \Facade\IgnitionContracts\Solution $solution */ | ||||
|             $title       = $solution->getSolutionTitle(); | ||||
|             /** @var \Spatie\Ignition\Contracts\Solution $solution */ | ||||
|             $title = $solution->getSolutionTitle(); | ||||
|             $description = $solution->getSolutionDescription(); | ||||
|             $links       = $solution->getDocumentationLinks(); | ||||
|             $links = $solution->getDocumentationLinks(); | ||||
|  | ||||
|             $description = trim((string) preg_replace("/\n/", "\n    ", $description)); | ||||
|  | ||||
|             $this->render(sprintf( | ||||
|                 '<fg=blue;options=bold>• </><fg=default;options=bold>%s</>: %s %s', | ||||
|                 '<fg=cyan;options=bold>i</>   <fg=default;options=bold>%s</>: %s %s', | ||||
|                 rtrim($title, '.'), | ||||
|                 $description, | ||||
|                 implode(', ', array_map(function (string $link) { | ||||
|                     return sprintf("\n    <fg=blue>%s</>", $link); | ||||
|                     return sprintf("\n      <fg=gray>%s</>", $link); | ||||
|                 }, $links)) | ||||
|             )); | ||||
|         } | ||||
| @@ -275,7 +275,7 @@ final class Writer implements WriterContract | ||||
|  | ||||
|             // getLine() might return null so cast to int to get 0 instead | ||||
|             $line = (int) $frame->getLine(); | ||||
|             $this->render('at <fg=green>' . $file . '</>' . ':<fg=green>' . $line . '</>'); | ||||
|             $this->render('at <fg=green>'.$file.'</>'.':<fg=green>'.$line.'</>'); | ||||
|  | ||||
|             $content = $this->highlighter->highlight((string) $frame->getFileContents(), (int) $frame->getLine()); | ||||
|  | ||||
| @@ -291,10 +291,11 @@ final class Writer implements WriterContract | ||||
|     protected function renderTrace(array $frames): WriterContract | ||||
|     { | ||||
|         $vendorFrames = 0; | ||||
|         $userFrames   = 0; | ||||
|         $userFrames = 0; | ||||
|         foreach ($frames as $i => $frame) { | ||||
|             if ($this->output->getVerbosity() < OutputInterface::VERBOSITY_VERBOSE && strpos($frame->getFile(), '/vendor/') !== false) { | ||||
|                 $vendorFrames++; | ||||
|  | ||||
|                 continue; | ||||
|             } | ||||
|  | ||||
| @@ -304,12 +305,12 @@ final class Writer implements WriterContract | ||||
|  | ||||
|             $userFrames++; | ||||
|  | ||||
|             $file     = $this->getFileRelativePath($frame->getFile()); | ||||
|             $line     = $frame->getLine(); | ||||
|             $class    = empty($frame->getClass()) ? '' : $frame->getClass() . '::'; | ||||
|             $file = $this->getFileRelativePath($frame->getFile()); | ||||
|             $line = $frame->getLine(); | ||||
|             $class = empty($frame->getClass()) ? '' : $frame->getClass().'::'; | ||||
|             $function = $frame->getFunction(); | ||||
|             $args     = $this->argumentFormatter->format($frame->getArgs()); | ||||
|             $pos      = str_pad((string) ((int) $i + 1), 4, ' '); | ||||
|             $args = $this->argumentFormatter->format($frame->getArgs()); | ||||
|             $pos = str_pad((string) ((int) $i + 1), 4, ' '); | ||||
|  | ||||
|             if ($vendorFrames > 0) { | ||||
|                 $this->output->write( | ||||
| @@ -319,7 +320,7 @@ final class Writer implements WriterContract | ||||
|             } | ||||
|  | ||||
|             $this->render("<fg=yellow>$pos</><fg=default;options=bold>$file</>:<fg=default;options=bold>$line</>"); | ||||
|             $this->render("<fg=white>    $class$function($args)</>", false); | ||||
|             $this->render("<fg=gray>    $class$function($args)</>", false); | ||||
|         } | ||||
|  | ||||
|         return $this; | ||||
| @@ -348,7 +349,7 @@ final class Writer implements WriterContract | ||||
|     { | ||||
|         $cwd = (string) getcwd(); | ||||
|  | ||||
|         if (!empty($cwd)) { | ||||
|         if (! empty($cwd)) { | ||||
|             return str_replace("$cwd/", '', $filePath); | ||||
|         } | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 RafficMohammed
					RafficMohammed