mirror of
https://github.com/pestphp/pest.git
synced 2026-07-26 19:40:03 +02:00
Compare commits
9 Commits
afb582616d
..
v4.7.5
| Author | SHA1 | Date | |
|---|---|---|---|
| 5dc49a71d6 | |||
| 1adb484d3f | |||
| aadf7e92a6 | |||
| df42b9ed7b | |||
| 632ae79c8b | |||
| ee2e97e932 | |||
| b561236325 | |||
| e685179b7e | |||
| ac8feafdcc |
@@ -2,7 +2,7 @@ name: Static Analysis
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [5.x]
|
branches: [4.x]
|
||||||
pull_request:
|
pull_request:
|
||||||
schedule:
|
schedule:
|
||||||
- cron: '0 9 * * *'
|
- cron: '0 9 * * *'
|
||||||
@@ -28,12 +28,12 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||||
|
|
||||||
- name: Setup PHP
|
- name: Setup PHP
|
||||||
uses: shivammathur/setup-php@f3e473d116dcccaddc5834248c87452386958240 # v2
|
uses: shivammathur/setup-php@f3e473d116dcccaddc5834248c87452386958240 # v2
|
||||||
with:
|
with:
|
||||||
php-version: 8.4
|
php-version: 8.3
|
||||||
tools: composer:v2
|
tools: composer:v2
|
||||||
coverage: none
|
coverage: none
|
||||||
extensions: sockets
|
extensions: sockets
|
||||||
@@ -44,17 +44,17 @@ jobs:
|
|||||||
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
|
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Cache Composer dependencies
|
- name: Cache Composer dependencies
|
||||||
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5
|
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v5
|
||||||
with:
|
with:
|
||||||
path: ${{ steps.composer-cache.outputs.dir }}
|
path: ${{ steps.composer-cache.outputs.dir }}
|
||||||
key: static-php-8.4-${{ matrix.dependency-version }}-composer-${{ hashFiles('**/composer.json', '**/composer.lock') }}
|
key: static-php-8.3-${{ matrix.dependency-version }}-composer-${{ hashFiles('**/composer.json', '**/composer.lock') }}
|
||||||
restore-keys: |
|
restore-keys: |
|
||||||
static-php-8.4-${{ matrix.dependency-version }}-composer-
|
static-php-8.3-${{ matrix.dependency-version }}-composer-
|
||||||
static-php-8.4-composer-
|
static-php-8.3-composer-
|
||||||
|
|
||||||
- name: Install Dependencies
|
- name: Install Dependencies
|
||||||
env:
|
env:
|
||||||
COMPOSER_ROOT_VERSION: 5.x-dev
|
COMPOSER_ROOT_VERSION: 4.x-dev
|
||||||
run: composer update --${{ matrix.dependency-version }} --no-interaction --no-progress --ansi
|
run: composer update --${{ matrix.dependency-version }} --no-interaction --no-progress --ansi
|
||||||
|
|
||||||
- name: Profanity Check
|
- name: Profanity Check
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ name: Tests
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [5.x]
|
branches: [4.x]
|
||||||
pull_request:
|
pull_request:
|
||||||
schedule:
|
schedule:
|
||||||
- cron: '0 9 * * *'
|
- cron: '0 9 * * *'
|
||||||
@@ -24,15 +24,18 @@ jobs:
|
|||||||
fail-fast: true
|
fail-fast: true
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-latest, macos-latest] # windows-latest
|
os: [ubuntu-latest, macos-latest] # windows-latest
|
||||||
symfony: ['8.0']
|
symfony: ['7.4', '8.0']
|
||||||
php: ['8.4', '8.5']
|
php: ['8.3', '8.4', '8.5']
|
||||||
dependency_version: [prefer-stable]
|
dependency_version: [prefer-stable]
|
||||||
|
exclude:
|
||||||
|
- php: '8.3'
|
||||||
|
symfony: '8.0'
|
||||||
|
|
||||||
name: PHP ${{ matrix.php }} - Symfony ^${{ matrix.symfony }} - ${{ matrix.os }} - ${{ matrix.dependency_version }}
|
name: PHP ${{ matrix.php }} - Symfony ^${{ matrix.symfony }} - ${{ matrix.os }} - ${{ matrix.dependency_version }}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||||
|
|
||||||
- name: Setup PHP
|
- name: Setup PHP
|
||||||
uses: shivammathur/setup-php@f3e473d116dcccaddc5834248c87452386958240 # v2
|
uses: shivammathur/setup-php@f3e473d116dcccaddc5834248c87452386958240 # v2
|
||||||
@@ -48,7 +51,7 @@ jobs:
|
|||||||
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
|
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Cache Composer dependencies
|
- name: Cache Composer dependencies
|
||||||
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5
|
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v5
|
||||||
with:
|
with:
|
||||||
path: ${{ steps.composer-cache.outputs.dir }}
|
path: ${{ steps.composer-cache.outputs.dir }}
|
||||||
key: ${{ matrix.os }}-php-${{ matrix.php }}-symfony-${{ matrix.symfony }}-composer-${{ hashFiles('**/composer.json', '**/composer.lock') }}
|
key: ${{ matrix.os }}-php-${{ matrix.php }}-symfony-${{ matrix.symfony }}-composer-${{ hashFiles('**/composer.json', '**/composer.lock') }}
|
||||||
@@ -64,7 +67,7 @@ jobs:
|
|||||||
- name: Install PHP dependencies
|
- name: Install PHP dependencies
|
||||||
shell: bash
|
shell: bash
|
||||||
env:
|
env:
|
||||||
COMPOSER_ROOT_VERSION: 5.x-dev
|
COMPOSER_ROOT_VERSION: 4.x-dev
|
||||||
run: composer update --${{ matrix.dependency_version }} --no-interaction --no-progress --ansi --with="symfony/console:^${{ matrix.symfony }}"
|
run: composer update --${{ matrix.dependency_version }} --no-interaction --no-progress --ansi --with="symfony/console:^${{ matrix.symfony }}"
|
||||||
|
|
||||||
- name: Unit Tests
|
- name: Unit Tests
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<p align="center">
|
<p align="center">
|
||||||
<img src="https://raw.githubusercontent.com/pestphp/art/master/v5/social.png" width="600" alt="PEST">
|
<img src="https://raw.githubusercontent.com/pestphp/art/master/v4/social.png" width="600" alt="PEST">
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<a href="https://github.com/pestphp/pest/actions"><img alt="GitHub Workflow Status (5.x)" src="https://img.shields.io/github/actions/workflow/status/pestphp/pest/tests.yml?branch=5.x&label=Tests%205.x"></a>
|
<a href="https://github.com/pestphp/pest/actions"><img alt="GitHub Workflow Status (4.x)" src="https://img.shields.io/github/actions/workflow/status/pestphp/pest/tests.yml?branch=4.x&label=Tests%204.x"></a>
|
||||||
<a href="https://packagist.org/packages/pestphp/pest"><img alt="Total Downloads" src="https://img.shields.io/packagist/dt/pestphp/pest"></a>
|
<a href="https://packagist.org/packages/pestphp/pest"><img alt="Total Downloads" src="https://img.shields.io/packagist/dt/pestphp/pest"></a>
|
||||||
<a href="https://packagist.org/packages/pestphp/pest"><img alt="Latest Version" src="https://img.shields.io/packagist/v/pestphp/pest"></a>
|
<a href="https://packagist.org/packages/pestphp/pest"><img alt="Latest Version" src="https://img.shields.io/packagist/v/pestphp/pest"></a>
|
||||||
<a href="https://packagist.org/packages/pestphp/pest"><img alt="License" src="https://img.shields.io/packagist/l/pestphp/pest"></a>
|
<a href="https://packagist.org/packages/pestphp/pest"><img alt="License" src="https://img.shields.io/packagist/l/pestphp/pest"></a>
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
|
|
||||||
------
|
------
|
||||||
|
|
||||||
> Pest v5 Now Available: **[Read the announcement »](https://pestphp.com/docs/pest-v5-is-here)**.
|
> Pest v4 Now Available: **[Read the announcement »](https://pestphp.com/docs/pest-v4-is-here-now-with-browser-testing)**.
|
||||||
|
|
||||||
**Pest** is an elegant PHP testing Framework with a focus on simplicity, meticulously designed to bring back the joy of testing in PHP.
|
**Pest** is an elegant PHP testing Framework with a focus on simplicity, meticulously designed to bring back the joy of testing in PHP.
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -2,10 +2,10 @@
|
|||||||
|
|
||||||
When releasing a new version of Pest there are some checks and updates that need to be done:
|
When releasing a new version of Pest there are some checks and updates that need to be done:
|
||||||
|
|
||||||
> **For Pest v4 you should use the `4.x` branch instead.**
|
> **For Pest v3 you should use the `3.x` branch instead.**
|
||||||
|
|
||||||
- Clear your local repository with: `git add . && git reset --hard && git checkout 5.x`
|
- Clear your local repository with: `git add . && git reset --hard && git checkout 4.x`
|
||||||
- On the GitHub repository, check the contents of [github.com/pestphp/pest/compare/{latest_version}...5.x](https://github.com/pestphp/pest/compare/{latest_version}...5.x)
|
- On the GitHub repository, check the contents of [github.com/pestphp/pest/compare/{latest_version}...4.x](https://github.com/pestphp/pest/compare/{latest_version}...4.x)
|
||||||
- Update the version number in [src/Pest.php](src/Pest.php)
|
- Update the version number in [src/Pest.php](src/Pest.php)
|
||||||
- Run the tests locally using: `composer test`
|
- Run the tests locally using: `composer test`
|
||||||
- Commit the Pest file with the message: `git commit -m "release: vX.X.X"`
|
- Commit the Pest file with the message: `git commit -m "release: vX.X.X"`
|
||||||
|
|||||||
+15
-15
@@ -17,20 +17,21 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"require": {
|
"require": {
|
||||||
"php": "^8.4",
|
"php": "^8.3.0",
|
||||||
"brianium/paratest": "^7.22.4",
|
"brianium/paratest": "^7.20.0",
|
||||||
|
"composer/xdebug-handler": "^3.0.5",
|
||||||
"nunomaduro/collision": "^8.9.4",
|
"nunomaduro/collision": "^8.9.4",
|
||||||
"nunomaduro/termwind": "^2.4.0",
|
"nunomaduro/termwind": "^2.4.0",
|
||||||
"pestphp/pest-plugin": "^5.0.0",
|
"pestphp/pest-plugin": "^4.0.0",
|
||||||
"pestphp/pest-plugin-arch": "^5.0.0",
|
"pestphp/pest-plugin-arch": "^4.0.2",
|
||||||
"pestphp/pest-plugin-mutate": "^5.0.0",
|
"pestphp/pest-plugin-mutate": "^4.0.1",
|
||||||
"pestphp/pest-plugin-profanity": "^5.0.0",
|
"pestphp/pest-plugin-profanity": "^4.2.1",
|
||||||
"phpunit/phpunit": "^13.1.8",
|
"phpunit/phpunit": "^12.5.30",
|
||||||
"symfony/process": "^8.1.0"
|
"symfony/process": "^7.4.13|^8.1.0"
|
||||||
},
|
},
|
||||||
"conflict": {
|
"conflict": {
|
||||||
"filp/whoops": "<2.18.3",
|
"filp/whoops": "<2.18.3",
|
||||||
"phpunit/phpunit": ">13.1.8",
|
"phpunit/phpunit": ">12.5.30",
|
||||||
"sebastian/exporter": "<7.0.0",
|
"sebastian/exporter": "<7.0.0",
|
||||||
"webmozart/assert": "<1.11.0"
|
"webmozart/assert": "<1.11.0"
|
||||||
},
|
},
|
||||||
@@ -58,12 +59,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"mrpunyapal/peststan": "^0.2.10",
|
"mrpunyapal/peststan": "^0.2.11",
|
||||||
"laravel/pao": "^1.1.0",
|
"pestphp/pest-dev-tools": "^4.1.0",
|
||||||
"pestphp/pest-dev-tools": "^5.0.0",
|
"pestphp/pest-plugin-browser": "^4.3.1",
|
||||||
"pestphp/pest-plugin-browser": "^5.0.0",
|
"pestphp/pest-plugin-type-coverage": "^4.0.4",
|
||||||
"pestphp/pest-plugin-type-coverage": "^5.0.0",
|
"psy/psysh": "^0.12.24"
|
||||||
"psy/psysh": "^0.12.23"
|
|
||||||
},
|
},
|
||||||
"minimum-stability": "dev",
|
"minimum-stability": "dev",
|
||||||
"prefer-stable": true,
|
"prefer-stable": true,
|
||||||
|
|||||||
@@ -4,7 +4,9 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
use Rector\CodingStyle\Rector\ArrowFunction\ArrowFunctionDelegatingCallToFirstClassCallableRector;
|
use Rector\CodingStyle\Rector\ArrowFunction\ArrowFunctionDelegatingCallToFirstClassCallableRector;
|
||||||
use Rector\Config\RectorConfig;
|
use Rector\Config\RectorConfig;
|
||||||
|
use Rector\DeadCode\Rector\ClassMethod\RemoveDuplicatedReturnSelfDocblockRector;
|
||||||
use Rector\DeadCode\Rector\ClassMethod\RemoveParentDelegatingConstructorRector;
|
use Rector\DeadCode\Rector\ClassMethod\RemoveParentDelegatingConstructorRector;
|
||||||
|
use Rector\DeadCode\Rector\ClassMethod\RemoveUselessUnionReturnDocblockRector;
|
||||||
use Rector\TypeDeclaration\Rector\ClassMethod\NarrowObjectReturnTypeRector;
|
use Rector\TypeDeclaration\Rector\ClassMethod\NarrowObjectReturnTypeRector;
|
||||||
use Rector\TypeDeclaration\Rector\ClassMethod\ReturnNeverTypeRector;
|
use Rector\TypeDeclaration\Rector\ClassMethod\ReturnNeverTypeRector;
|
||||||
|
|
||||||
@@ -18,6 +20,8 @@ return RectorConfig::configure()
|
|||||||
ArrowFunctionDelegatingCallToFirstClassCallableRector::class,
|
ArrowFunctionDelegatingCallToFirstClassCallableRector::class,
|
||||||
NarrowObjectReturnTypeRector::class,
|
NarrowObjectReturnTypeRector::class,
|
||||||
RemoveParentDelegatingConstructorRector::class,
|
RemoveParentDelegatingConstructorRector::class,
|
||||||
|
RemoveDuplicatedReturnSelfDocblockRector::class,
|
||||||
|
RemoveUselessUnionReturnDocblockRector::class,
|
||||||
])
|
])
|
||||||
->withPreparedSets(
|
->withPreparedSets(
|
||||||
deadCode: true,
|
deadCode: true,
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
<div>
|
<div>
|
||||||
<span class="text-gray mr-1">- </span>
|
<span class="text-gray mr-1">- </span>
|
||||||
<span>composer require pestphp/pest-plugin-browser:^5.0 --dev</span>
|
<span>composer require pestphp/pest-plugin-browser:^4.0 --dev</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ final readonly class Configuration
|
|||||||
*/
|
*/
|
||||||
public function in(string ...$targets): UsesCall
|
public function in(string ...$targets): UsesCall
|
||||||
{
|
{
|
||||||
return new UsesCall($this->filename, [])->in(...$targets);
|
return (new UsesCall($this->filename, []))->in(...$targets);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -60,7 +60,7 @@ final readonly class Configuration
|
|||||||
*/
|
*/
|
||||||
public function group(string ...$groups): UsesCall
|
public function group(string ...$groups): UsesCall
|
||||||
{
|
{
|
||||||
return new UsesCall($this->filename, [])->group(...$groups);
|
return (new UsesCall($this->filename, []))->group(...$groups);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -68,7 +68,7 @@ final readonly class Configuration
|
|||||||
*/
|
*/
|
||||||
public function only(): void
|
public function only(): void
|
||||||
{
|
{
|
||||||
new BeforeEachCall(TestSuite::getInstance(), $this->filename)->only();
|
(new BeforeEachCall(TestSuite::getInstance(), $this->filename))->only();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+13
-5
@@ -130,7 +130,7 @@ final class Expectation
|
|||||||
if (getenv('PARATEST') !== false || isset($_SERVER['COLLISION_PRINTER'])) {
|
if (getenv('PARATEST') !== false || isset($_SERVER['COLLISION_PRINTER'])) {
|
||||||
ob_start();
|
ob_start();
|
||||||
var_dump($this->value, ...$arguments);
|
var_dump($this->value, ...$arguments);
|
||||||
$output = (string) ob_get_clean();
|
$output = ob_get_clean();
|
||||||
|
|
||||||
throw new ExpectationFailedException($output);
|
throw new ExpectationFailedException($output);
|
||||||
}
|
}
|
||||||
@@ -244,7 +244,7 @@ final class Expectation
|
|||||||
if ($callbacks[$index] instanceof Closure) {
|
if ($callbacks[$index] instanceof Closure) {
|
||||||
$callbacks[$index](new self($value), new self($key));
|
$callbacks[$index](new self($value), new self($key));
|
||||||
} else {
|
} else {
|
||||||
new self($value)->toEqual($callbacks[$index]);
|
(new self($value))->toEqual($callbacks[$index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
$index = isset($callbacks[$index + 1]) ? $index + 1 : 0;
|
$index = isset($callbacks[$index + 1]) ? $index + 1 : 0;
|
||||||
@@ -921,7 +921,15 @@ final class Expectation
|
|||||||
|
|
||||||
return Targeted::make(
|
return Targeted::make(
|
||||||
$this,
|
$this,
|
||||||
fn (ObjectDescription $object): bool => array_all($interfaces, fn (string $interface): bool => isset($object->reflectionClass) && $object->reflectionClass->implementsInterface($interface)),
|
function (ObjectDescription $object) use ($interfaces): bool {
|
||||||
|
foreach ($interfaces as $interface) {
|
||||||
|
if (! isset($object->reflectionClass) || ! $object->reflectionClass->implementsInterface($interface)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
},
|
||||||
"to implement '".implode("', '", $interfaces)."'",
|
"to implement '".implode("', '", $interfaces)."'",
|
||||||
FileLineFinder::where(fn (string $line): bool => str_contains($line, 'class')),
|
FileLineFinder::where(fn (string $line): bool => str_contains($line, 'class')),
|
||||||
);
|
);
|
||||||
@@ -1136,8 +1144,8 @@ final class Expectation
|
|||||||
$this,
|
$this,
|
||||||
fn (ObjectDescription $object): bool => isset($object->reflectionClass)
|
fn (ObjectDescription $object): bool => isset($object->reflectionClass)
|
||||||
&& $object->reflectionClass->isEnum()
|
&& $object->reflectionClass->isEnum()
|
||||||
&& new ReflectionEnum($object->name)->isBacked() // @phpstan-ignore-line
|
&& (new ReflectionEnum($object->name))->isBacked() // @phpstan-ignore-line
|
||||||
&& (string) new ReflectionEnum($object->name)->getBackingType() === $backingType, // @phpstan-ignore-line
|
&& (string) (new ReflectionEnum($object->name))->getBackingType() === $backingType, // @phpstan-ignore-line
|
||||||
'to be '.$backingType.' backed enum',
|
'to be '.$backingType.' backed enum',
|
||||||
FileLineFinder::where(fn (string $line): bool => str_contains($line, 'class')),
|
FileLineFinder::where(fn (string $line): bool => str_contains($line, 'class')),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -576,7 +576,15 @@ final readonly class OppositeExpectation
|
|||||||
|
|
||||||
return Targeted::make(
|
return Targeted::make(
|
||||||
$original,
|
$original,
|
||||||
fn (ObjectDescription $object): bool => array_all($traits, fn (string $trait): bool => ! (isset($object->reflectionClass) && in_array($trait, $object->reflectionClass->getTraitNames(), true))),
|
function (ObjectDescription $object) use ($traits): bool {
|
||||||
|
foreach ($traits as $trait) {
|
||||||
|
if (isset($object->reflectionClass) && in_array($trait, $object->reflectionClass->getTraitNames(), true)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
},
|
||||||
"not to use traits '".implode("', '", $traits)."'",
|
"not to use traits '".implode("', '", $traits)."'",
|
||||||
FileLineFinder::where(fn (string $line): bool => str_contains($line, 'class')),
|
FileLineFinder::where(fn (string $line): bool => str_contains($line, 'class')),
|
||||||
);
|
);
|
||||||
@@ -596,7 +604,15 @@ final readonly class OppositeExpectation
|
|||||||
|
|
||||||
return Targeted::make(
|
return Targeted::make(
|
||||||
$original,
|
$original,
|
||||||
fn (ObjectDescription $object): bool => array_all($interfaces, fn (string $interface): bool => ! (isset($object->reflectionClass) && $object->reflectionClass->implementsInterface($interface))),
|
function (ObjectDescription $object) use ($interfaces): bool {
|
||||||
|
foreach ($interfaces as $interface) {
|
||||||
|
if (isset($object->reflectionClass) && $object->reflectionClass->implementsInterface($interface)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
},
|
||||||
"not to implement '".implode("', '", $interfaces)."'",
|
"not to implement '".implode("', '", $interfaces)."'",
|
||||||
FileLineFinder::where(fn (string $line): bool => str_contains($line, 'class')),
|
FileLineFinder::where(fn (string $line): bool => str_contains($line, 'class')),
|
||||||
);
|
);
|
||||||
@@ -798,11 +814,13 @@ final readonly class OppositeExpectation
|
|||||||
|
|
||||||
$exporter = Exporter::default();
|
$exporter = Exporter::default();
|
||||||
|
|
||||||
|
$toString = fn (mixed $argument): string => $exporter->shortenedExport($argument);
|
||||||
|
|
||||||
throw new ExpectationFailedException(sprintf(
|
throw new ExpectationFailedException(sprintf(
|
||||||
'Expecting %s not %s %s.',
|
'Expecting %s not %s %s.',
|
||||||
$exporter->shortenedExport($this->original->value),
|
$toString($this->original->value),
|
||||||
strtolower((string) preg_replace('/(?<!\ )[A-Z]/', ' $0', $name)),
|
strtolower((string) preg_replace('/(?<!\ )[A-Z]/', ' $0', $name)),
|
||||||
implode(' ', array_map(fn (mixed $argument): string => $exporter->export($argument), $arguments)),
|
implode(' ', array_map(fn (mixed $argument): string => $toString($argument), $arguments)),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -834,8 +852,8 @@ final readonly class OppositeExpectation
|
|||||||
$original,
|
$original,
|
||||||
fn (ObjectDescription $object): bool => isset($object->reflectionClass) === false
|
fn (ObjectDescription $object): bool => isset($object->reflectionClass) === false
|
||||||
|| ! $object->reflectionClass->isEnum()
|
|| ! $object->reflectionClass->isEnum()
|
||||||
|| ! new \ReflectionEnum($object->name)->isBacked() // @phpstan-ignore-line
|
|| ! (new \ReflectionEnum($object->name))->isBacked() // @phpstan-ignore-line
|
||||||
|| (string) new \ReflectionEnum($object->name)->getBackingType() !== $backingType, // @phpstan-ignore-line
|
|| (string) (new \ReflectionEnum($object->name))->getBackingType() !== $backingType, // @phpstan-ignore-line
|
||||||
'not to be '.$backingType.' backed enum',
|
'not to be '.$backingType.' backed enum',
|
||||||
FileLineFinder::where(fn (string $line): bool => str_contains($line, 'class')),
|
FileLineFinder::where(fn (string $line): bool => str_contains($line, 'class')),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -94,7 +94,8 @@ final class TestCaseFactory
|
|||||||
$filename = (string) preg_replace_callback('~^(?P<drive>[a-z]+:\\\)~i', static fn (array $match): string => strtolower($match['drive']), $filename);
|
$filename = (string) preg_replace_callback('~^(?P<drive>[a-z]+:\\\)~i', static fn (array $match): string => strtolower($match['drive']), $filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
$filename = str_replace('\\\\', '\\', addslashes((string) realpath($filename)));
|
$realpath = (string) realpath($filename);
|
||||||
|
$filename = str_replace('\\\\', '\\', addslashes($realpath));
|
||||||
$rootPath = TestSuite::getInstance()->rootPath;
|
$rootPath = TestSuite::getInstance()->rootPath;
|
||||||
$relativePath = str_replace($rootPath.DIRECTORY_SEPARATOR, '', $filename);
|
$relativePath = str_replace($rootPath.DIRECTORY_SEPARATOR, '', $filename);
|
||||||
|
|
||||||
@@ -149,6 +150,8 @@ final class TestCaseFactory
|
|||||||
|
|
||||||
$attributesCode = Attributes::code($this->attributes);
|
$attributesCode = Attributes::code($this->attributes);
|
||||||
|
|
||||||
|
$filenameLiteral = var_export($realpath, true);
|
||||||
|
|
||||||
$methodsCode = implode('', array_map(
|
$methodsCode = implode('', array_map(
|
||||||
fn (TestCaseMethodFactory $methodFactory): string => $methodFactory->buildForEvaluation(),
|
fn (TestCaseMethodFactory $methodFactory): string => $methodFactory->buildForEvaluation(),
|
||||||
$methods
|
$methods
|
||||||
@@ -166,7 +169,7 @@ final class TestCaseFactory
|
|||||||
final class $className extends $baseClass implements $hasPrintableTestCaseClassFQN {
|
final class $className extends $baseClass implements $hasPrintableTestCaseClassFQN {
|
||||||
$traitsCode
|
$traitsCode
|
||||||
|
|
||||||
public static \$__filename = '$filename';
|
public static \$__filename = $filenameLiteral;
|
||||||
|
|
||||||
$methodsCode
|
$methodsCode
|
||||||
}
|
}
|
||||||
@@ -197,7 +200,7 @@ final class TestCaseFactory
|
|||||||
|
|
||||||
if (
|
if (
|
||||||
$method->closure instanceof \Closure &&
|
$method->closure instanceof \Closure &&
|
||||||
new \ReflectionFunction($method->closure)->isStatic()
|
(new \ReflectionFunction($method->closure))->isStatic()
|
||||||
) {
|
) {
|
||||||
|
|
||||||
throw new TestClosureMustNotBeStatic($method);
|
throw new TestClosureMustNotBeStatic($method);
|
||||||
|
|||||||
@@ -936,7 +936,7 @@ final class Expectation
|
|||||||
|
|
||||||
if ($exception instanceof Closure) {
|
if ($exception instanceof Closure) {
|
||||||
$callback = $exception;
|
$callback = $exception;
|
||||||
$parameters = new ReflectionFunction($exception)->getParameters();
|
$parameters = (new ReflectionFunction($exception))->getParameters();
|
||||||
|
|
||||||
if (count($parameters) !== 1) {
|
if (count($parameters) !== 1) {
|
||||||
throw new InvalidArgumentException('The given closure must have a single parameter type-hinted as the class string.');
|
throw new InvalidArgumentException('The given closure must have a single parameter type-hinted as the class string.');
|
||||||
@@ -1142,22 +1142,6 @@ final class Expectation
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Asserts that the value is a ULID.
|
|
||||||
*
|
|
||||||
* @return self<TValue>
|
|
||||||
*/
|
|
||||||
public function toBeUlid(string $message = ''): self
|
|
||||||
{
|
|
||||||
if (! is_string($this->value)) {
|
|
||||||
InvalidExpectationValue::expected('string');
|
|
||||||
}
|
|
||||||
|
|
||||||
Assert::assertTrue(Str::isUlid($this->value), $message);
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Asserts that the value is between 2 specified values
|
* Asserts that the value is between 2 specified values
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ final readonly class HigherOrderExpectationTypeExtension implements ExpressionTy
|
|||||||
|
|
||||||
$varType = $scope->getType($expr->var);
|
$varType = $scope->getType($expr->var);
|
||||||
|
|
||||||
if (! new ObjectType(HigherOrderExpectation::class)->isSuperTypeOf($varType)->yes()) {
|
if (! (new ObjectType(HigherOrderExpectation::class))->isSuperTypeOf($varType)->yes()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -53,7 +53,9 @@ final class UsesCall
|
|||||||
$this->targets = [$filename];
|
$this->targets = [$filename];
|
||||||
}
|
}
|
||||||
|
|
||||||
#[\Deprecated(message: 'Use `pest()->printer()->compact()` instead.')]
|
/**
|
||||||
|
* @deprecated Use `pest()->printer()->compact()` instead.
|
||||||
|
*/
|
||||||
public function compact(): self
|
public function compact(): self
|
||||||
{
|
{
|
||||||
DefaultPrinter::compact(true);
|
DefaultPrinter::compact(true);
|
||||||
|
|||||||
+1
-1
@@ -6,7 +6,7 @@ namespace Pest;
|
|||||||
|
|
||||||
function version(): string
|
function version(): string
|
||||||
{
|
{
|
||||||
return '5.0.0-rc.10';
|
return '4.7.5';
|
||||||
}
|
}
|
||||||
|
|
||||||
function testDirectory(string $file = ''): string
|
function testDirectory(string $file = ''): string
|
||||||
|
|||||||
@@ -178,7 +178,13 @@ final class Parallel implements HandlesArguments
|
|||||||
{
|
{
|
||||||
$arguments = new ArgvInput;
|
$arguments = new ArgvInput;
|
||||||
|
|
||||||
return array_any(self::UNSUPPORTED_ARGUMENTS, fn (string|array $unsupportedArgument): bool => $arguments->hasParameterOption($unsupportedArgument));
|
foreach (self::UNSUPPORTED_ARGUMENTS as $unsupportedArgument) {
|
||||||
|
if ($arguments->hasParameterOption($unsupportedArgument)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ namespace Pest\Plugins\Parallel\Paratest;
|
|||||||
use const DIRECTORY_SEPARATOR;
|
use const DIRECTORY_SEPARATOR;
|
||||||
|
|
||||||
use NunoMaduro\Collision\Adapters\Phpunit\Support\ResultReflection;
|
use NunoMaduro\Collision\Adapters\Phpunit\Support\ResultReflection;
|
||||||
|
use ParaTest\Coverage\CoverageMerger;
|
||||||
use ParaTest\JUnit\LogMerger;
|
use ParaTest\JUnit\LogMerger;
|
||||||
use ParaTest\JUnit\Writer;
|
use ParaTest\JUnit\Writer;
|
||||||
use ParaTest\Options;
|
use ParaTest\Options;
|
||||||
@@ -24,17 +25,11 @@ use PHPUnit\TestRunner\TestResult\Facade as TestResultFacade;
|
|||||||
use PHPUnit\TestRunner\TestResult\TestResult;
|
use PHPUnit\TestRunner\TestResult\TestResult;
|
||||||
use PHPUnit\TextUI\Configuration\CodeCoverageFilterRegistry;
|
use PHPUnit\TextUI\Configuration\CodeCoverageFilterRegistry;
|
||||||
use PHPUnit\Util\ExcludeList;
|
use PHPUnit\Util\ExcludeList;
|
||||||
use ReflectionProperty;
|
|
||||||
use SebastianBergmann\CodeCoverage\Node\Builder;
|
|
||||||
use SebastianBergmann\CodeCoverage\Serialization\Merger;
|
|
||||||
use SebastianBergmann\CodeCoverage\StaticAnalysis\FileAnalyser;
|
|
||||||
use SebastianBergmann\CodeCoverage\StaticAnalysis\ParsingSourceAnalyser;
|
|
||||||
use SebastianBergmann\Timer\Timer;
|
use SebastianBergmann\Timer\Timer;
|
||||||
use SplFileInfo;
|
use SplFileInfo;
|
||||||
use Symfony\Component\Console\Output\OutputInterface;
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
use Symfony\Component\Process\PhpExecutableFinder;
|
use Symfony\Component\Process\PhpExecutableFinder;
|
||||||
|
|
||||||
use function array_filter;
|
|
||||||
use function array_merge;
|
use function array_merge;
|
||||||
use function array_merge_recursive;
|
use function array_merge_recursive;
|
||||||
use function array_shift;
|
use function array_shift;
|
||||||
@@ -452,33 +447,10 @@ final class WrapperRunner implements RunnerInterface
|
|||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$coverageFiles = [];
|
$coverageMerger = new CoverageMerger($coverageManager->codeCoverage());
|
||||||
foreach ($this->coverageFiles as $fileInfo) {
|
foreach ($this->coverageFiles as $coverageFile) {
|
||||||
$realPath = $fileInfo->getRealPath();
|
$coverageMerger->addCoverageFromFile($coverageFile);
|
||||||
if ($realPath !== false && $realPath !== '') {
|
|
||||||
$coverageFiles[] = $realPath;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
$serializedCoverage = (new Merger)->merge($coverageFiles);
|
|
||||||
|
|
||||||
$report = (new Builder(new FileAnalyser(new ParsingSourceAnalyser, false, false)))->build(
|
|
||||||
$serializedCoverage['codeCoverage'],
|
|
||||||
$serializedCoverage['testResults'],
|
|
||||||
$serializedCoverage['basePath'],
|
|
||||||
);
|
|
||||||
$codeCoverage = $coverageManager->codeCoverage();
|
|
||||||
$codeCoverage->excludeUncoveredFiles();
|
|
||||||
|
|
||||||
$mergedData = $serializedCoverage['codeCoverage'];
|
|
||||||
$basePath = $serializedCoverage['basePath'];
|
|
||||||
if ($basePath !== '') {
|
|
||||||
foreach ($mergedData->coveredFiles() as $relativePath) {
|
|
||||||
$mergedData->renameFile($relativePath, $basePath.DIRECTORY_SEPARATOR.$relativePath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$codeCoverage->setData($mergedData);
|
|
||||||
$codeCoverage->setTests($serializedCoverage['testResults']);
|
|
||||||
(new ReflectionProperty(\SebastianBergmann\CodeCoverage\CodeCoverage::class, 'cachedReport'))->setValue($codeCoverage, $report);
|
|
||||||
|
|
||||||
$coverageManager->generateReports(
|
$coverageManager->generateReports(
|
||||||
$this->printer->printer,
|
$this->printer->printer,
|
||||||
|
|||||||
@@ -187,11 +187,11 @@ final class Shard implements AddsOutput, HandlesArguments, Terminable
|
|||||||
*/
|
*/
|
||||||
private function allTests(array $arguments): array
|
private function allTests(array $arguments): array
|
||||||
{
|
{
|
||||||
$output = new Process([
|
$output = (new Process([
|
||||||
'php',
|
'php',
|
||||||
...$this->removeParallelArguments($arguments),
|
...$this->removeParallelArguments($arguments),
|
||||||
'--list-tests',
|
'--list-tests',
|
||||||
])->setTimeout(120)->mustRun()->getOutput();
|
]))->setTimeout(120)->mustRun()->getOutput();
|
||||||
|
|
||||||
preg_match_all('/ - (?:P\\\\)?(Tests\\\\[^:]+)::/', $output, $matches);
|
preg_match_all('/ - (?:P\\\\)?(Tests\\\\[^:]+)::/', $output, $matches);
|
||||||
|
|
||||||
|
|||||||
+9
-4
@@ -219,8 +219,11 @@ final class Tia implements AddsOutput, HandlesArguments, Terminable
|
|||||||
if (! $watchPatterns->isEnabled()) {
|
if (! $watchPatterns->isEnabled()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (! $watchPatterns->isLocally()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return ! ($watchPatterns->isLocally() && self::argumentPresent('--ci', $arguments));
|
return ! self::argumentPresent('--ci', $arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -251,7 +254,7 @@ final class Tia implements AddsOutput, HandlesArguments, Terminable
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (str_starts_with($arg, "$argument=")) {
|
if (str_starts_with((string) $arg, "$argument=")) { // @phpstan-ignore-line
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -624,7 +627,7 @@ final class Tia implements AddsOutput, HandlesArguments, Terminable
|
|||||||
private function handleParent(array $arguments, string $projectRoot, bool $forceRebuild): array
|
private function handleParent(array $arguments, string $projectRoot, bool $forceRebuild): array
|
||||||
{
|
{
|
||||||
$this->watchPatterns->useDefaults($projectRoot);
|
$this->watchPatterns->useDefaults($projectRoot);
|
||||||
$this->branch = new ChangedFiles($projectRoot)->currentBranch() ?? 'main';
|
$this->branch = (new ChangedFiles($projectRoot))->currentBranch() ?? 'main';
|
||||||
|
|
||||||
$fingerprint = Fingerprint::compute($projectRoot);
|
$fingerprint = Fingerprint::compute($projectRoot);
|
||||||
$this->startFingerprint = $fingerprint;
|
$this->startFingerprint = $fingerprint;
|
||||||
@@ -687,7 +690,7 @@ final class Tia implements AddsOutput, HandlesArguments, Terminable
|
|||||||
*/
|
*/
|
||||||
private function handleWorker(array $arguments, string $projectRoot, bool $recordingGlobal, bool $replayingGlobal): array
|
private function handleWorker(array $arguments, string $projectRoot, bool $recordingGlobal, bool $replayingGlobal): array
|
||||||
{
|
{
|
||||||
$this->branch = new ChangedFiles($projectRoot)->currentBranch() ?? 'main';
|
$this->branch = (new ChangedFiles($projectRoot))->currentBranch() ?? 'main';
|
||||||
|
|
||||||
if ($replayingGlobal) {
|
if ($replayingGlobal) {
|
||||||
$this->installWorkerReplay($projectRoot);
|
$this->installWorkerReplay($projectRoot);
|
||||||
@@ -1489,6 +1492,8 @@ final class Tia implements AddsOutput, HandlesArguments, Terminable
|
|||||||
}
|
}
|
||||||
|
|
||||||
foreach ($arguments as $index => $arg) {
|
foreach ($arguments as $index => $arg) {
|
||||||
|
$arg = (string) $arg; // @phpstan-ignore-line
|
||||||
|
|
||||||
if ($arg === '') {
|
if ($arg === '') {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1289,7 +1289,13 @@ final class Graph
|
|||||||
/** @param array<string, array<int, string>> $edges */
|
/** @param array<string, array<int, string>> $edges */
|
||||||
private function anyTestUses(array $edges, string $component): bool
|
private function anyTestUses(array $edges, string $component): bool
|
||||||
{
|
{
|
||||||
return array_any($edges, fn (array $components): bool => in_array($component, $components, true));
|
foreach ($edges as $components) {
|
||||||
|
if (in_array($component, $components, true)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function pruneMissingTests(): void
|
public function pruneMissingTests(): void
|
||||||
|
|||||||
@@ -386,6 +386,12 @@ final class JsModuleGraph
|
|||||||
|
|
||||||
private static function hasViteConfig(string $projectRoot): bool
|
private static function hasViteConfig(string $projectRoot): bool
|
||||||
{
|
{
|
||||||
return array_any(self::VITE_CONFIG_NAMES, fn (string $name): bool => is_file($projectRoot.DIRECTORY_SEPARATOR.$name));
|
foreach (self::VITE_CONFIG_NAMES as $name) {
|
||||||
|
if (is_file($projectRoot.DIRECTORY_SEPARATOR.$name)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,15 @@ final class TableExtractor
|
|||||||
}
|
}
|
||||||
|
|
||||||
$prefix = strtolower(substr($trimmed, 0, 6));
|
$prefix = strtolower(substr($trimmed, 0, 6));
|
||||||
$matched = array_any(self::DML_PREFIXES, fn (string $dml): bool => str_starts_with($prefix, $dml));
|
|
||||||
|
$matched = false;
|
||||||
|
foreach (self::DML_PREFIXES as $dml) {
|
||||||
|
if (str_starts_with($prefix, $dml)) {
|
||||||
|
$matched = true;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (! $matched) {
|
if (! $matched) {
|
||||||
return [];
|
return [];
|
||||||
|
|||||||
@@ -94,7 +94,15 @@ final readonly class TestPaths
|
|||||||
if (in_array($relativePath, $this->files, true)) {
|
if (in_array($relativePath, $this->files, true)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
$matchesSuffix = array_any($this->suffixes, fn (string $suffix): bool => str_ends_with($relativePath, $suffix));
|
|
||||||
|
$matchesSuffix = false;
|
||||||
|
foreach ($this->suffixes as $suffix) {
|
||||||
|
if (str_ends_with($relativePath, $suffix)) {
|
||||||
|
$matchesSuffix = true;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (! $matchesSuffix) {
|
if (! $matchesSuffix) {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -253,17 +253,35 @@ final class WatchPatterns
|
|||||||
|
|
||||||
private function patternTargetsDotfiles(string $pattern): bool
|
private function patternTargetsDotfiles(string $pattern): bool
|
||||||
{
|
{
|
||||||
return array_any(explode('/', str_replace('\\', '/', $pattern)), fn (string $segment): bool => $segment !== '' && $segment[0] === '.');
|
foreach (explode('/', str_replace('\\', '/', $pattern)) as $segment) {
|
||||||
|
if ($segment !== '' && $segment[0] === '.') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function touchesVcs(string $file): bool
|
private function touchesVcs(string $file): bool
|
||||||
{
|
{
|
||||||
return array_any(explode('/', $file), fn (string $segment): bool => in_array($segment, self::VCS_DIRS, true));
|
foreach (explode('/', $file) as $segment) {
|
||||||
|
if (in_array($segment, self::VCS_DIRS, true)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function touchesDotfile(string $file): bool
|
private function touchesDotfile(string $file): bool
|
||||||
{
|
{
|
||||||
return array_any(explode('/', $file), fn (string $segment): bool => $segment !== '' && $segment[0] === '.');
|
foreach (explode('/', $file) as $segment) {
|
||||||
|
if ($segment !== '' && $segment[0] === '.') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function excludeMatches(string $exclude, string $file): bool
|
private function excludeMatches(string $exclude, string $file): bool
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ final class XdebugRestarter implements Restarter
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
new XdebugHandler('pest')->check();
|
(new XdebugHandler('pest'))->check();
|
||||||
}
|
}
|
||||||
|
|
||||||
private function xdebugIsCoverageOnly(): bool
|
private function xdebugIsCoverageOnly(): bool
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ use Pest\Plugins\Tia\CoverageMerger;
|
|||||||
use SebastianBergmann\CodeCoverage\CodeCoverage;
|
use SebastianBergmann\CodeCoverage\CodeCoverage;
|
||||||
use SebastianBergmann\CodeCoverage\Node\Directory;
|
use SebastianBergmann\CodeCoverage\Node\Directory;
|
||||||
use SebastianBergmann\CodeCoverage\Node\File;
|
use SebastianBergmann\CodeCoverage\Node\File;
|
||||||
use SebastianBergmann\CodeCoverage\Report\Facade;
|
|
||||||
use SebastianBergmann\Environment\Runtime;
|
use SebastianBergmann\Environment\Runtime;
|
||||||
use Symfony\Component\Console\Output\OutputInterface;
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
|
||||||
@@ -96,18 +95,10 @@ final class Coverage
|
|||||||
$codeCoverage = require $reportPath;
|
$codeCoverage = require $reportPath;
|
||||||
unlink($reportPath);
|
unlink($reportPath);
|
||||||
|
|
||||||
// @phpstan-ignore-next-line
|
$totalCoverage = $codeCoverage->getReport()->percentageOfExecutedLines();
|
||||||
if (is_array($codeCoverage)) {
|
|
||||||
$facade = Facade::fromSerializedData($codeCoverage);
|
|
||||||
|
|
||||||
/** @var Directory<File|Directory> $report */
|
/** @var Directory<File|Directory> $report */
|
||||||
$report = (fn (): Directory => $this->report)->call($facade);
|
$report = $codeCoverage->getReport();
|
||||||
} else {
|
|
||||||
/** @var Directory<File|Directory> $report */
|
|
||||||
$report = $codeCoverage->getReport();
|
|
||||||
}
|
|
||||||
|
|
||||||
$totalCoverage = $report->percentageOfExecutedLines();
|
|
||||||
|
|
||||||
foreach ($report->getIterator() as $file) {
|
foreach ($report->getIterator() as $file) {
|
||||||
if (! $file instanceof File) {
|
if (! $file instanceof File) {
|
||||||
|
|||||||
@@ -86,17 +86,4 @@ final readonly class Exporter
|
|||||||
|
|
||||||
return (string) preg_replace(array_keys($map), array_values($map), $this->exporter->shortenedExport($value));
|
return (string) preg_replace(array_keys($map), array_values($map), $this->exporter->shortenedExport($value));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Exports a value into a full single-line string without truncation.
|
|
||||||
*/
|
|
||||||
public function export(mixed $value): string
|
|
||||||
{
|
|
||||||
$map = [
|
|
||||||
'#\\\n\s*#' => '',
|
|
||||||
'# Object \(\.{3}\)#' => '',
|
|
||||||
];
|
|
||||||
|
|
||||||
return (string) preg_replace(array_keys($map), array_values($map), $this->exporter->export($value));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ final class HigherOrderMessage
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($this->hasHigherOrderCallable()) {
|
if ($this->hasHigherOrderCallable()) {
|
||||||
return new HigherOrderCallables($target)->{$this->name}(...$this->arguments);
|
return (new HigherOrderCallables($target))->{$this->name}(...$this->arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ final class HigherOrderMessageCollection
|
|||||||
*/
|
*/
|
||||||
public function addWhen(callable $condition, string $filename, int $line, string $name, ?array $arguments): void
|
public function addWhen(callable $condition, string $filename, int $line, string $name, ?array $arguments): void
|
||||||
{
|
{
|
||||||
$this->messages[] = new HigherOrderMessage($filename, $line, $name, $arguments)->when($condition);
|
$this->messages[] = (new HigherOrderMessage($filename, $line, $name, $arguments))->when($condition);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ final class HigherOrderTapProxy
|
|||||||
return $this->target->{$property};
|
return $this->target->{$property};
|
||||||
}
|
}
|
||||||
|
|
||||||
$className = new ReflectionClass($this->target)->getName();
|
$className = (new ReflectionClass($this->target))->getName();
|
||||||
|
|
||||||
if (str_starts_with($className, 'P\\')) {
|
if (str_starts_with($className, 'P\\')) {
|
||||||
$className = substr($className, 2);
|
$className = substr($className, 2);
|
||||||
@@ -60,7 +60,7 @@ final class HigherOrderTapProxy
|
|||||||
$filename = Backtrace::file();
|
$filename = Backtrace::file();
|
||||||
$line = Backtrace::line();
|
$line = Backtrace::line();
|
||||||
|
|
||||||
return new HigherOrderMessage($filename, $line, $methodName, $arguments)
|
return (new HigherOrderMessage($filename, $line, $methodName, $arguments))
|
||||||
->call($this->target);
|
->call($this->target);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -181,7 +181,7 @@ final class Reflection
|
|||||||
*/
|
*/
|
||||||
public static function getFunctionArguments(Closure $function): array
|
public static function getFunctionArguments(Closure $function): array
|
||||||
{
|
{
|
||||||
$parameters = new ReflectionFunction($function)->getParameters();
|
$parameters = (new ReflectionFunction($function))->getParameters();
|
||||||
$arguments = [];
|
$arguments = [];
|
||||||
|
|
||||||
foreach ($parameters as $parameter) {
|
foreach ($parameters as $parameter) {
|
||||||
@@ -207,7 +207,7 @@ final class Reflection
|
|||||||
|
|
||||||
public static function getFunctionVariable(Closure $function, string $key): mixed
|
public static function getFunctionVariable(Closure $function, string $key): mixed
|
||||||
{
|
{
|
||||||
return new ReflectionFunction($function)->getStaticVariables()[$key] ?? null;
|
return (new ReflectionFunction($function))->getStaticVariables()[$key] ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -98,14 +98,6 @@ final class Str
|
|||||||
return preg_match('/^[\da-f]{8}-[\da-f]{4}-[\da-f]{4}-[\da-f]{4}-[\da-f]{12}$/iD', $value) > 0;
|
return preg_match('/^[\da-f]{8}-[\da-f]{4}-[\da-f]{4}-[\da-f]{4}-[\da-f]{12}$/iD', $value) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine if a given value is a valid ULID.
|
|
||||||
*/
|
|
||||||
public static function isUlid(string $value): bool
|
|
||||||
{
|
|
||||||
return preg_match('/^[0-9A-HJKMNP-TV-Z]{26}$/', $value) > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a describe block as `$describeDescription` → `$testDescription` format.
|
* Creates a describe block as `$describeDescription` → `$testDescription` format.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
Pest Testing Framework 5.0.0-rc.10.
|
Pest Testing Framework 4.7.5.
|
||||||
|
|
||||||
USAGE: pest <file> [options]
|
USAGE: pest <file> [options]
|
||||||
|
|
||||||
@@ -45,7 +45,6 @@
|
|||||||
--filter [pattern] ............................... Filter which tests to run
|
--filter [pattern] ............................... Filter which tests to run
|
||||||
--exclude-filter [pattern] .. Exclude tests for the specified filter pattern
|
--exclude-filter [pattern] .. Exclude tests for the specified filter pattern
|
||||||
--test-suffix [suffixes] Only search for test in files with specified suffix(es). Default: Test.php,.phpt
|
--test-suffix [suffixes] Only search for test in files with specified suffix(es). Default: Test.php,.phpt
|
||||||
--test-files-file [file] Only run test files listed in file (one file by line)
|
|
||||||
|
|
||||||
EXECUTION OPTIONS:
|
EXECUTION OPTIONS:
|
||||||
--parallel ........................................... Run tests in parallel
|
--parallel ........................................... Run tests in parallel
|
||||||
@@ -126,12 +125,12 @@
|
|||||||
LOGGING OPTIONS:
|
LOGGING OPTIONS:
|
||||||
--log-junit [file] .......... Write test results in JUnit XML format to file
|
--log-junit [file] .......... Write test results in JUnit XML format to file
|
||||||
--log-otr [file] Write test results in Open Test Reporting XML format to file
|
--log-otr [file] Write test results in Open Test Reporting XML format to file
|
||||||
|
--include-git-information Include Git information in Open Test Reporting XML logfile
|
||||||
--log-teamcity [file] ........ Write test results in TeamCity format to file
|
--log-teamcity [file] ........ Write test results in TeamCity format to file
|
||||||
--testdox-html [file] .. Write test results in TestDox format (HTML) to file
|
--testdox-html [file] .. Write test results in TestDox format (HTML) to file
|
||||||
--testdox-text [file] Write test results in TestDox format (plain text) to file
|
--testdox-text [file] Write test results in TestDox format (plain text) to file
|
||||||
--log-events-text [file] ............... Stream events as plain text to file
|
--log-events-text [file] ............... Stream events as plain text to file
|
||||||
--log-events-verbose-text [file] Stream events as plain text with extended information to file
|
--log-events-verbose-text [file] Stream events as plain text with extended information to file
|
||||||
--include-git-information ..... Include Git information in supported formats
|
|
||||||
--no-logging ....... Ignore logging configured in the XML configuration file
|
--no-logging ....... Ignore logging configured in the XML configuration file
|
||||||
|
|
||||||
CODE COVERAGE OPTIONS:
|
CODE COVERAGE OPTIONS:
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
|
|
||||||
Pest Testing Framework 5.0.0-rc.10.
|
Pest Testing Framework 4.7.5.
|
||||||
|
|
||||||
|
|||||||
@@ -752,13 +752,6 @@
|
|||||||
✓ passes as not truthy with ('0')
|
✓ passes as not truthy with ('0')
|
||||||
✓ failures
|
✓ failures
|
||||||
✓ failures with custom message
|
✓ failures with custom message
|
||||||
✓ not failures
|
|
||||||
|
|
||||||
PASS Tests\Features\Expect\toBeUlid
|
|
||||||
✓ failures with wrong type
|
|
||||||
✓ pass
|
|
||||||
✓ failures
|
|
||||||
✓ failures with message
|
|
||||||
✓ not failures
|
✓ not failures
|
||||||
|
|
||||||
PASS Tests\Features\Expect\toBeUppercase
|
PASS Tests\Features\Expect\toBeUppercase
|
||||||
@@ -1703,8 +1696,6 @@
|
|||||||
PASS Tests\Unit\Expectations\OppositeExpectation
|
PASS Tests\Unit\Expectations\OppositeExpectation
|
||||||
✓ it throw expectation failed exception with string argument
|
✓ it throw expectation failed exception with string argument
|
||||||
✓ it throw expectation failed exception with array argument
|
✓ it throw expectation failed exception with array argument
|
||||||
✓ it does not truncate long string arguments in error message
|
|
||||||
✓ it does not truncate custom error message when using not()
|
|
||||||
|
|
||||||
PASS Tests\Unit\Overrides\ThrowableBuilder
|
PASS Tests\Unit\Overrides\ThrowableBuilder
|
||||||
✓ collision editor can be added to the stack trace
|
✓ collision editor can be added to the stack trace
|
||||||
@@ -1761,6 +1752,10 @@
|
|||||||
✓ output format → it returns a 32-character hex xxh128 hash
|
✓ output format → it returns a 32-character hex xxh128 hash
|
||||||
✓ output format → it returns a stable hash for empty content
|
✓ output format → it returns a stable hash for empty content
|
||||||
|
|
||||||
|
PASS Tests\Unit\Plugins\Tia\IsEnabledForRun
|
||||||
|
✓ does not throw when an integer --random-order-seed is passed as a separate argv element
|
||||||
|
✓ still detects --tia when an integer argument is present
|
||||||
|
|
||||||
PASS Tests\Unit\Preset
|
PASS Tests\Unit\Preset
|
||||||
✓ preset invalid name
|
✓ preset invalid name
|
||||||
✓ preset → myFramework
|
✓ preset → myFramework
|
||||||
@@ -1946,4 +1941,4 @@
|
|||||||
✓ pass with dataset with ('my-datas-set-value')
|
✓ pass with dataset with ('my-datas-set-value')
|
||||||
✓ within describe → pass with dataset with ('my-datas-set-value')
|
✓ within describe → pass with dataset with ('my-datas-set-value')
|
||||||
|
|
||||||
Tests: 2 deprecated, 4 warnings, 5 incomplete, 2 notices, 40 todos, 35 skipped, 1335 passed (3024 assertions)
|
Tests: 2 deprecated, 4 warnings, 5 incomplete, 2 notices, 40 todos, 35 skipped, 1330 passed (3010 assertions)
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
use Pest\Exceptions\InvalidExpectationValue;
|
|
||||||
use PHPUnit\Framework\ExpectationFailedException;
|
|
||||||
|
|
||||||
test('failures with wrong type', function () {
|
|
||||||
expect([])->toBeUlid();
|
|
||||||
})->throws(InvalidExpectationValue::class, 'Invalid expectation value type. Expected [string].');
|
|
||||||
|
|
||||||
test('pass', function () {
|
|
||||||
expect('01ARZ3NDEKTSV4RRFFQ69G5FAV')->toBeUlid();
|
|
||||||
expect('01BX5ZZKBKACTAV9WEVGEMMVRE')->toBeUlid();
|
|
||||||
expect('7ZZZZZZZZZ0000000000000000')->toBeUlid();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('failures', function () {
|
|
||||||
expect('foo')->toBeUlid();
|
|
||||||
})->throws(ExpectationFailedException::class);
|
|
||||||
|
|
||||||
test('failures with message', function () {
|
|
||||||
expect('bar')->toBeUlid('oh no!');
|
|
||||||
})->throws(ExpectationFailedException::class, 'oh no!');
|
|
||||||
|
|
||||||
test('not failures', function () {
|
|
||||||
expect('foo')->not->toBeUlid();
|
|
||||||
});
|
|
||||||
@@ -14,17 +14,3 @@ it('throw expectation failed exception with array argument', function (): void {
|
|||||||
|
|
||||||
$expectation->throwExpectationFailedException('toBe', ['bar']);
|
$expectation->throwExpectationFailedException('toBe', ['bar']);
|
||||||
})->throws(ExpectationFailedException::class, "Expecting 'foo' not to be 'bar'.");
|
})->throws(ExpectationFailedException::class, "Expecting 'foo' not to be 'bar'.");
|
||||||
|
|
||||||
it('does not truncate long string arguments in error message', function (): void {
|
|
||||||
$expectation = new OppositeExpectation(expect('foo'));
|
|
||||||
|
|
||||||
$longMessage = 'Very long error message. Very long error message. Very long error message.';
|
|
||||||
|
|
||||||
$expectation->throwExpectationFailedException('toBe', [$longMessage]);
|
|
||||||
})->throws(ExpectationFailedException::class, 'Very long error message. Very long error message. Very long error message.');
|
|
||||||
|
|
||||||
it('does not truncate custom error message when using not()', function (): void {
|
|
||||||
$longMessage = 'This is a very detailed custom error message that should not be truncated in the output.';
|
|
||||||
|
|
||||||
expect(true)->not()->toBeTrue($longMessage);
|
|
||||||
})->throws(ExpectationFailedException::class, 'This is a very detailed custom error message that should not be truncated in the output.');
|
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Pest\Plugins\Tia;
|
||||||
|
|
||||||
|
test('does not throw when an integer --random-order-seed is passed as a separate argv element', function () {
|
||||||
|
// Mirrors the parallel worker argv (see bin/worker.php), where
|
||||||
|
// `--random-order-seed` and its value arrive as separate items and the
|
||||||
|
// seed value is an int rather than a string. Regression test for the
|
||||||
|
// str_starts_with() TypeError in Tia::argumentPresent() — the same class
|
||||||
|
// of bug as #1206, which was only fixed in HandleArguments.
|
||||||
|
$arguments = ['--order-by=random', '--random-order-seed', 1782350398];
|
||||||
|
|
||||||
|
expect(Tia::isEnabledForRun($arguments))->toBeFalse();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('still detects --tia when an integer argument is present', function () {
|
||||||
|
$arguments = ['--tia', '--random-order-seed', 1782350398];
|
||||||
|
|
||||||
|
expect(Tia::isEnabledForRun($arguments))->toBeTrue();
|
||||||
|
});
|
||||||
@@ -24,13 +24,13 @@ test('parallel', function () use ($run) {
|
|||||||
$file = file_get_contents(__FILE__);
|
$file = file_get_contents(__FILE__);
|
||||||
$file = preg_replace(
|
$file = preg_replace(
|
||||||
'/\$expected = \'.*?\';/',
|
'/\$expected = \'.*?\';/',
|
||||||
"\$expected = '2 deprecated, 4 warnings, 5 incomplete, 3 notices, 40 todos, 27 skipped, 1319 passed (2973 assertions)';",
|
"\$expected = '2 deprecated, 4 warnings, 5 incomplete, 3 notices, 40 todos, 27 skipped, 1314 passed (2959 assertions)';",
|
||||||
$file,
|
$file,
|
||||||
);
|
);
|
||||||
file_put_contents(__FILE__, $file);
|
file_put_contents(__FILE__, $file);
|
||||||
}
|
}
|
||||||
|
|
||||||
$expected = '2 deprecated, 4 warnings, 5 incomplete, 3 notices, 40 todos, 27 skipped, 1319 passed (2973 assertions)';
|
$expected = '2 deprecated, 4 warnings, 5 incomplete, 3 notices, 40 todos, 27 skipped, 1314 passed (2959 assertions)';
|
||||||
|
|
||||||
expect($output)
|
expect($output)
|
||||||
->toContain("Tests: {$expected}")
|
->toContain("Tests: {$expected}")
|
||||||
|
|||||||
Reference in New Issue
Block a user