Merge branch '2.x' into dirty_integration

This commit is contained in:
Nuno Maduro
2023-01-10 21:34:18 +00:00
committed by GitHub
65 changed files with 823 additions and 266 deletions

View File

@ -44,6 +44,30 @@ final class Backtrace
return $current[self::FILE];
}
/**
* Returns the current datasets file.
*/
public static function datasetsFile(): string
{
$current = null;
foreach (debug_backtrace(self::BACKTRACE_OPTIONS) as $trace) {
assert(array_key_exists(self::FILE, $trace));
if (Str::endsWith($trace['file'], 'Bootstrappers/BootFiles.php') || Str::endsWith($trace[self::FILE], 'overrides/Runner/TestSuiteLoader.php')) {
break;
}
$current = $trace;
}
if ($current === null) {
throw ShouldNotHappen::fromMessage('Dataset file not found.');
}
return $current[self::FILE];
}
/**
* Returns the filename that called the current function/method.
*/

View File

@ -22,8 +22,8 @@ final class ChainableClosure
throw ShouldNotHappen::fromMessage('$this not bound to chainable closure.');
}
\Pest\Support\Closure::bind($closure, $this, $this::class)(...func_get_args());
\Pest\Support\Closure::bind($next, $this, $this::class)(...func_get_args());
\Pest\Support\Closure::bind($closure, $this, self::class)(...func_get_args());
\Pest\Support\Closure::bind($next, $this, self::class)(...func_get_args());
};
}

View File

@ -16,7 +16,7 @@ final class Container
private static ?Container $instance = null;
/**
* @var array<string, mixed>
* @var array<string, object|string>
*/
private array $instances = [];
@ -25,37 +25,30 @@ final class Container
*/
public static function getInstance(): self
{
if (static::$instance === null) {
static::$instance = new self();
if (self::$instance === null) {
self::$instance = new self();
}
return static::$instance;
return self::$instance;
}
/**
* Gets a dependency from the container.
*
* @template TObject of object
*
* @param class-string<TObject> $id
* @return TObject
*/
public function get(string $id): mixed
public function get(string $id): object|string
{
if (! array_key_exists($id, $this->instances)) {
/** @var class-string $id */
$this->instances[$id] = $this->build($id);
}
/** @var TObject $concrete */
$concrete = $this->instances[$id];
return $concrete;
return $this->instances[$id];
}
/**
* Adds the given instance to the container.
*/
public function add(string $id, mixed $instance): void
public function add(string $id, object|string $instance): void
{
$this->instances[$id] = $instance;
}
@ -68,7 +61,7 @@ final class Container
* @param class-string<TObject> $id
* @return TObject
*/
private function build(string $id): mixed
private function build(string $id): object
{
$reflectionClass = new ReflectionClass($id);
@ -77,7 +70,7 @@ final class Container
if ($constructor !== null) {
$params = array_map(
function (ReflectionParameter $param) use ($id) {
function (ReflectionParameter $param) use ($id): object|string {
$candidate = Reflection::getParameterClassName($param);
if ($candidate === null) {
@ -90,7 +83,6 @@ final class Container
}
}
// @phpstan-ignore-next-line
return $this->get($candidate);
},
$constructor->getParameters()

View File

@ -10,9 +10,9 @@ 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;
use function Termwind\render;
use function Termwind\renderUsing;
use function Termwind\terminal;
/**
* @internal
@ -42,15 +42,15 @@ final class Coverage
return false;
}
if ($runtime->hasXdebug()) {
if (version_compare((string) phpversion('xdebug'), '3.1', '>=')) {
if (! in_array('coverage', xdebug_info('mode'), true)) {
return false;
}
}
if (! $runtime->hasXdebug()) {
return true;
}
return true;
if (! version_compare((string) phpversion('xdebug'), '3.1', '>=')) {
return true;
}
return in_array('coverage', xdebug_info('mode'), true);
}
/**
@ -83,10 +83,6 @@ final class Coverage
$codeCoverage = require $reportPath;
unlink($reportPath);
$totalWidth = (new Terminal())->getWidth();
$dottedLineLength = $totalWidth - 6;
$totalCoverage = $codeCoverage->getReport()->percentageOfExecutedLines();
/** @var Directory<File|Directory> $report */
@ -103,36 +99,23 @@ final class Coverage
$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) + 2 + $linesExecutedTakenSize; // adding 3 space and percent sign
$color = $percentage === '100.0' ? 'green' : ($percentage === '0.0' ? 'red' : 'yellow');
$percentage = sprintf(
'<fg=%s>%s</>',
$percentage === '100.0' ? 'green' : ($percentage === '0.0' ? 'red' : 'yellow'),
$percentage
);
$truncateAt = max(1, terminal()->width() - 12);
$output->writeln(sprintf(
' %s <fg=gray>%s</> %s <fg=gray>%%</>',
$name,
str_repeat('.', max($dottedLineLength - $takenSize, 1)),
$percentage
));
renderUsing($output);
render(<<<HTML
<div class="flex mx-2">
<span class="truncate-{$truncateAt}">{$name}</span>
<span class="flex-1 content-repeat-[.] text-gray mx-1"></span>
<span class="text-{$color}">{$percentage}%</span>
</div>
HTML);
}
$totalCoverageAsString = $totalCoverage->asFloat() === 0.0

View File

@ -0,0 +1,38 @@
<?php
declare(strict_types=1);
namespace Pest\Support;
/**
* @internal
*/
final class DatasetInfo
{
public const DATASETS_DIR_NAME = 'Datasets';
public const DATASETS_FILE_NAME = 'Datasets.php';
public static function isInsideADatasetsDirectory(string $file): bool
{
return basename(dirname($file)) === self::DATASETS_DIR_NAME;
}
public static function isADatasetsFile(string $file): bool
{
return basename($file) === self::DATASETS_FILE_NAME;
}
public static function scope(string $file): string
{
if (self::isInsideADatasetsDirectory($file)) {
return dirname($file, 2);
}
if (self::isADatasetsFile($file)) {
return dirname($file);
}
return $file;
}
}

View File

@ -10,6 +10,10 @@ use Throwable;
/**
* @internal
*
* @template TProxy
*
* @mixin TProxy
*/
final class HigherOrderTapProxy
{

View File

@ -12,6 +12,7 @@ use ReflectionException;
use ReflectionFunction;
use ReflectionNamedType;
use ReflectionParameter;
use ReflectionProperty;
use ReflectionUnionType;
/**
@ -95,7 +96,7 @@ final class Reflection
$reflectionProperty = null;
while ($reflectionProperty === null) {
while (! $reflectionProperty instanceof ReflectionProperty) {
try {
/* @var ReflectionProperty $reflectionProperty */
$reflectionProperty = $reflectionClass->getProperty($property);
@ -127,7 +128,7 @@ final class Reflection
$reflectionProperty = null;
while ($reflectionProperty === null) {
while (! $reflectionProperty instanceof ReflectionProperty) {
try {
/* @var ReflectionProperty $reflectionProperty */
$reflectionProperty = $reflectionClass->getProperty($property);

View File

@ -56,7 +56,7 @@ final class Str
{
$code = str_replace(' ', '_', $code);
return (string) preg_replace('/[^A-Z_a-z0-9\\\\]/', '', $code);
return (string) preg_replace('/[^A-Z_a-z0-9]/', '_', $code);
}
/**