Compare commits

..

36 Commits

Author SHA1 Message Date
67f217852c chore: uses stable version of collision and termwind 2024-10-15 17:17:09 +01:00
1bad148487 release: v3.4.0 2024-10-15 15:13:19 +01:00
e24f137b8e fix: deprecation 2024-10-15 15:09:26 +01:00
6d9189f3f5 feat: php 8.4 support 2024-10-15 15:04:30 +01:00
1513ede73b release: v3.3.2 2024-10-12 12:36:44 +01:00
8c65197881 chore: bumps depndencies 2024-10-12 12:33:57 +01:00
3f65af9fdf Merge pull request #1292 from olivernybroe/policy-suffix
Add Policy suffix to policies
2024-10-11 09:34:05 +01:00
42d89814e3 Merge pull request #1293 from AbdellahBoutmad/dir
modify test command in contrbuting.md
2024-10-11 09:33:41 +01:00
1e3156a5b6 release: v3.3.1 2024-10-11 09:31:24 +01:00
97713c0832 chore: bumps dependencies 2024-10-11 09:31:16 +01:00
62b0e3c9df modify test command in contrbuting.md 2024-10-10 12:34:04 +01:00
647de2f1cf Add Policy suffix to policies 2024-10-10 08:08:10 +02:00
0a7bff0d24 release: v3.3.0 2024-10-06 19:25:27 +01:00
7618434580 chore: uses phpunit v11.4.0 2024-10-06 19:25:20 +01:00
1e0bb88b73 release: v3.2.5 2024-10-01 11:55:18 +01:00
83b76d7c2e chore: bumps dependencies 2024-10-01 11:51:26 +01:00
5a870b3940 chore: style changes 2024-10-01 11:51:16 +01:00
1115c64186 chore: style changes 2024-10-01 11:48:14 +01:00
e38a271ca2 Merge pull request #1279 from midnite81/bug/declare-strict-types-with-comments-above
Strict types expectation allows for comments above declaration
2024-09-29 19:12:06 +01:00
43703ab40a Merge pull request #1280 from CamKem/fix/middleware-method-preset
Fix: Add middleware to the allowable public methods for Laravel Preset
2024-09-29 19:11:40 +01:00
86452765a4 fix: add middleware to the allowable public methods on the laravel preset 2024-09-29 16:07:39 +10:00
b8a1b7e5cc Add tests for strict types expectation
Introduced new test cases to ensure strict type declaration handling. Files with and without strict types are tested, including scenarios with comments preceding the declaration. Updated the regex in `Expectation.php` to accommodate comments and whitespaces before the `declare(strict_types=1)` statement.
2024-09-28 17:31:33 +01:00
5fe79d9c18 release: v3.2.4 2024-09-26 23:53:39 +01:00
2744da4292 Merge pull request #1277 from MuhammedAlkhudiry/ignore-handler-in-laravel-preset
ignore App\Exceptions\Handler.php in arch laravel preset
2024-09-26 23:47:26 +01:00
87f4e5e7b3 fix 2024-09-26 16:44:30 +03:00
bb3decf3cc ignore App\Exceptions\Handler.php in arch laravel preset 2024-09-26 16:41:43 +03:00
4e2987d438 release: v3.2.3 2024-09-25 16:19:39 +01:00
a25158bce8 Merge pull request #1275 from jeremynikolic/laravel-presets-ignore-concerns
feat: add ignoring of Concerns folder inside App\Enums and App\Features
2024-09-25 16:16:26 +01:00
49e77b1d4c feat: add ignoring of Concerns folder inside App\Enums and App\Features 2024-09-25 17:12:42 +02:00
989e43d1a0 release: v3.2.2 2024-09-24 10:23:43 +01:00
7cd42aafd8 fix: auto-complete on presets 2024-09-24 10:23:32 +01:00
48a1de273f release: v3.2.1 2024-09-23 14:09:55 +01:00
970e16e949 Ignores 2024-09-23 14:08:30 +01:00
432ff221c6 fix: missing != and !== on new toUseStrictEquality arch expectation 2024-09-23 14:08:21 +01:00
a55da85dd2 release: v3.2.0 2024-09-23 13:14:03 +01:00
f291cd1603 chore: bumps dependencies 2024-09-23 13:11:49 +01:00
27 changed files with 198 additions and 60 deletions

View File

@ -37,12 +37,7 @@ jobs:
- name: Install PHP dependencies
shell: bash
run: |
if [[ "${{ matrix.php }}" == "8.4" ]]; then
composer update --${{ matrix.dependency_version }} --no-interaction --no-progress --ansi --with="symfony/console:^${{ matrix.symfony }}" --ignore-platform-req=php
else
composer update --${{ matrix.dependency_version }} --no-interaction --no-progress --ansi --with="symfony/console:^${{ matrix.symfony }}"
fi
run: composer update --${{ matrix.dependency_version }} --no-interaction --no-progress --ansi --with="symfony/console:^${{ matrix.symfony }}"
- name: Unit Tests
run: composer test:unit
@ -51,5 +46,4 @@ jobs:
run: composer test:parallel
- name: Integration Tests
if: ${{ matrix.php != '8.4' }}
run: composer test:integration

View File

@ -42,7 +42,7 @@ composer test
Check types:
```bash
composer test:types
composer test:type:check
```
Unit tests:

View File

@ -1,5 +1,7 @@
#!/usr/bin/env php
<?php declare(strict_types=1);
<?php
declare(strict_types=1);
use Pest\Kernel;
use Pest\Panic;
@ -37,7 +39,7 @@ use Symfony\Component\Console\Output\ConsoleOutput;
if (str_contains($value, '--test-directory=')) {
unset($arguments[$key]);
} else if ($value === '--test-directory') {
} elseif ($value === '--test-directory') {
unset($arguments[$key]);
if (isset($arguments[$key + 1])) {
@ -62,7 +64,7 @@ use Symfony\Component\Console\Output\ConsoleOutput;
if (str_contains($value, '--assignee=')) {
unset($arguments[$key]);
} else if ($value === '--assignee') {
} elseif ($value === '--assignee') {
unset($arguments[$key]);
if (isset($arguments[$key + 1])) {
@ -72,7 +74,7 @@ use Symfony\Component\Console\Output\ConsoleOutput;
if (str_contains($value, '--issue=')) {
unset($arguments[$key]);
} else if ($value === '--issue') {
} elseif ($value === '--issue') {
unset($arguments[$key]);
if (isset($arguments[$key + 1])) {
@ -82,7 +84,7 @@ use Symfony\Component\Console\Output\ConsoleOutput;
if (str_contains($value, '--ticket=')) {
unset($arguments[$key]);
} else if ($value === '--ticket') {
} elseif ($value === '--ticket') {
unset($arguments[$key]);
if (isset($arguments[$key + 1])) {
@ -92,7 +94,7 @@ use Symfony\Component\Console\Output\ConsoleOutput;
if (str_contains($value, '--pr=')) {
unset($arguments[$key]);
} else if ($value === '--pr') {
} elseif ($value === '--pr') {
unset($arguments[$key]);
if (isset($arguments[$key + 1])) {
@ -102,7 +104,7 @@ use Symfony\Component\Console\Output\ConsoleOutput;
if (str_contains($value, '--pull-request=')) {
unset($arguments[$key]);
} else if ($value === '--pull-request') {
} elseif ($value === '--pull-request') {
unset($arguments[$key]);
if (isset($arguments[$key + 1])) {
@ -117,7 +119,6 @@ use Symfony\Component\Console\Output\ConsoleOutput;
}
}
// Used when Pest is required using composer.
$vendorPath = dirname(__DIR__, 4).'/vendor/autoload.php';
@ -134,7 +135,7 @@ use Symfony\Component\Console\Output\ConsoleOutput;
// Get $rootPath based on $autoloadPath
$rootPath = dirname($autoloadPath, 2);
$input = new ArgvInput();
$input = new ArgvInput;
$testSuite = TestSuite::getInstance(
$rootPath,
@ -146,11 +147,11 @@ use Symfony\Component\Console\Output\ConsoleOutput;
}
if ($todo) {
$testSuite->tests->addTestCaseMethodFilter(new TodoTestCaseFilter());
$testSuite->tests->addTestCaseMethodFilter(new TodoTestCaseFilter);
}
if ($notes) {
$testSuite->tests->addTestCaseMethodFilter(new NotesTestCaseFilter());
$testSuite->tests->addTestCaseMethodFilter(new NotesTestCaseFilter);
}
if ($assignee = $input->getParameterOption('--assignee')) {

View File

@ -18,16 +18,17 @@
],
"require": {
"php": "^8.2.0",
"brianium/paratest": "^7.5.4",
"nunomaduro/collision": "^8.4.0",
"nunomaduro/termwind": "^2.1.0",
"brianium/paratest": "^7.6.0",
"nunomaduro/collision": "^8.5.0",
"nunomaduro/termwind": "^2.2.0",
"pestphp/pest-plugin": "^3.0.0",
"pestphp/pest-plugin-arch": "^3.0.0",
"pestphp/pest-plugin-mutate": "^3.0.4",
"phpunit/phpunit": "^11.3.6"
"pestphp/pest-plugin-mutate": "^3.0.5",
"phpunit/phpunit": "^11.4.1"
},
"conflict": {
"phpunit/phpunit": ">11.3.6",
"filp/whoops": "<2.16.0",
"phpunit/phpunit": ">11.4.1",
"sebastian/exporter": "<6.0.0",
"webmozart/assert": "<1.11.0"
},
@ -52,9 +53,9 @@
]
},
"require-dev": {
"pestphp/pest-dev-tools": "^3.0.0",
"pestphp/pest-plugin-type-coverage": "^3.0.0",
"symfony/process": "^7.1.3"
"pestphp/pest-dev-tools": "^3.3.0",
"pestphp/pest-plugin-type-coverage": "^3.1.0",
"symfony/process": "^7.1.5"
},
"minimum-stability": "dev",
"prefer-stable": true,

View File

@ -1,6 +1,5 @@
includes:
- vendor/phpstan/phpstan-strict-rules/rules.neon
- vendor/ergebnis/phpstan-rules/rules.neon
- vendor/thecodingmachine/phpstan-strict-rules/phpstan-strict-rules.neon
parameters:
@ -12,12 +11,4 @@ parameters:
reportUnmatchedIgnoredErrors: true
ignoreErrors:
- "#has a nullable return type declaration.#"
- "#Language construct isset\\(\\) should not be used.#"
- "#is not allowed to extend#"
- "#is concrete, but does not have a Test suffix#"
- "#with a nullable type declaration#"
- "#type mixed is not subtype of native#"
- "# with null as default value#"
- "#has parameter \\$closure with default value.#"
- "#has parameter \\$description with default value.#"

View File

@ -27,17 +27,20 @@ final class Laravel extends AbstractPreset
->ignoring('App\Enums');
$this->expectations[] = expect('App\Enums')
->toBeEnums();
->toBeEnums()
->ignoring('App\Enums\Concerns');
$this->expectations[] = expect('App\Features')
->toBeClasses();
->toBeClasses()
->ignoring('App\Features\Concerns');
$this->expectations[] = expect('App\Features')
->toHaveMethod('resolve');
$this->expectations[] = expect('App\Exceptions')
->classes()
->toImplement('Throwable');
->toImplement('Throwable')
->ignoring('App\Exceptions\Handler');
$this->expectations[] = expect('App')
->not->toImplement(Throwable::class)
@ -149,7 +152,7 @@ final class Laravel extends AbstractPreset
->toOnlyBeUsedIn('App\Http');
$this->expectations[] = expect('App\Http\Controllers')
->not->toHavePublicMethodsBesides(['__construct', '__invoke', 'index', 'show', 'create', 'store', 'edit', 'update', 'destroy']);
->not->toHavePublicMethodsBesides(['__construct', '__invoke', 'index', 'show', 'create', 'store', 'edit', 'update', 'destroy', 'middleware']);
$this->expectations[] = expect([
'dd',
@ -159,5 +162,9 @@ final class Laravel extends AbstractPreset
'exit',
'ray',
])->not->toBeUsed();
$this->expectations[] = expect('App\Policies')
->classes()
->toHaveSuffix('Policy');
}
}

View File

@ -21,6 +21,7 @@ final class Strict extends AbstractPreset
fn (Expectation $namespace): ArchExpectation => $namespace->classes()->not->toHaveProtectedMethods(),
fn (Expectation $namespace): ArchExpectation => $namespace->classes()->not->toBeAbstract(),
fn (Expectation $namespace): ArchExpectation => $namespace->toUseStrictTypes(),
fn (Expectation $namespace): ArchExpectation => $namespace->toUseStrictEquality(),
fn (Expectation $namespace): ArchExpectation => $namespace->classes()->toBeFinal(),
);

View File

@ -18,12 +18,12 @@ final class BootOverrides implements Bootstrapper
* @var array<string, string>
*/
public const FILES = [
'c96b1cb57d7fc8e649f4c13a8abe418c2541bcfab194fb6702b99f777f52ee84' => 'Runner/Filter/NameFilterIterator.php',
'53c246e5f416a39817ac81124cdd64ea8403038d01d7a202e1ffa486fbdf3fa7' => 'Runner/Filter/NameFilterIterator.php',
'a4a43de01f641c6944ee83d963795a46d32b5206b5ab3bbc6cce76e67190acbf' => 'Runner/ResultCache/DefaultResultCache.php',
'd0e81317889ad88c707db4b08a94cadee4c9010d05ff0a759f04e71af5efed89' => 'Runner/TestSuiteLoader.php',
'3bb609b0d3bf6dee8df8d6cd62a3c8ece823c4bb941eaaae39e3cb267171b9d2' => 'TextUI/Command/Commands/WarmCodeCoverageCacheCommand.php',
'8abdad6413329c6fe0d7d44a8b9926e390af32c0b3123f3720bb9c5bbc6fbb7e' => 'TextUI/Output/Default/ProgressPrinter/Subscriber/TestSkippedSubscriber.php',
'43883b7e5811886cf3731c8ed6304d5a77078d9731e1e505abc2da36bde19f3e' => 'TextUI/TestSuiteFilterProcessor.php',
'b4250fc3ffad5954624cb5e682fd940b874e8d3422fa1ee298bd7225e1aa5fc2' => 'TextUI/TestSuiteFilterProcessor.php',
'357d5cd7007f8559b26e1b8cdf43bb6fb15b51b79db981779da6f31b7ec39dad' => 'Event/Value/ThrowableBuilder.php',
'676273f1fe483877cf2d95c5aedbf9ae5d6a8e2f4c12d6ce716df6591e6db023' => 'Logging/JUnit/JunitXmlLogger.php',
];

View File

@ -223,7 +223,7 @@ final class Expectation
throw new BadMethodCallException('Expectation value is not iterable.');
}
if (count($callbacks) == 0) {
if ($callbacks === []) {
throw new InvalidArgumentException('No sequence expectations defined.');
}
@ -264,7 +264,7 @@ final class Expectation
$matched = false;
foreach ($expressions as $key => $callback) {
if ($subject != $key) {
if ($subject != $key) { // @pest-arch-ignore-line
continue;
}
@ -380,7 +380,7 @@ final class Expectation
if (self::hasExtend($name)) {
$extend = self::$extends[$name]->bindTo($this, Expectation::class);
if ($extend != false) {
if ($extend != false) { // @pest-arch-ignore-line
return $extend;
}
}
@ -509,12 +509,25 @@ final class Expectation
{
return Targeted::make(
$this,
fn (ObjectDescription $object): bool => (bool) preg_match('/^<\?php\s+declare\(.*?strict_types\s?=\s?1.*?\);/', (string) file_get_contents($object->path)),
fn (ObjectDescription $object): bool => (bool) preg_match('/^<\?php\s*(\/\*[\s\S]*?\*\/|\/\/[^\r\n]*(?:\r?\n|$)|\s)*declare\s*\(\s*strict_types\s*=\s*1\s*\)\s*;/m', (string) file_get_contents($object->path)),
'to use strict types',
FileLineFinder::where(fn (string $line): bool => str_contains($line, '<?php')),
);
}
/**
* Asserts that the given expectation target uses strict equality.
*/
public function toUseStrictEquality(): ArchExpectation
{
return Targeted::make(
$this,
fn (ObjectDescription $object): bool => ! str_contains((string) file_get_contents($object->path), ' == ') && ! str_contains((string) file_get_contents($object->path), ' != '),
'to use strict equality',
FileLineFinder::where(fn (string $line): bool => str_contains($line, ' == ') || str_contains($line, ' != ')),
);
}
/**
* Asserts that the given expectation target is final.
*/

View File

@ -152,6 +152,19 @@ final readonly class OppositeExpectation
);
}
/**
* Asserts that the given expectation target does not use the strict equality operator.
*/
public function toUseStrictEquality(): ArchExpectation
{
return Targeted::make(
$this->original,
fn (ObjectDescription $object): bool => ! str_contains((string) file_get_contents($object->path), ' === ') && ! str_contains((string) file_get_contents($object->path), ' !== '),
'to use strict equality',
FileLineFinder::where(fn (string $line): bool => str_contains($line, ' === ') || str_contains($line, ' !== ')),
);
}
/**
* Asserts that the given expectation target is not final.
*/

View File

@ -166,7 +166,7 @@ final class TestCaseFactory
}
PHP;
eval($classCode); // @phpstan-ignore-line
eval($classCode);
} catch (ParseError $caught) {
throw new RuntimeException(sprintf(
"Unable to create test case for test file at %s. \n %s",

View File

@ -40,7 +40,7 @@ final class KernelDump
*/
public function disable(): void
{
@ob_clean(); // @phpstan-ignore-line
@ob_clean();
if ($this->buffer !== '') {
$this->flush();

View File

@ -150,7 +150,7 @@ final readonly class Converter
{
if ($testSuite instanceof TestSuiteForTestMethodWithDataProvider) {
$firstTest = $this->getFirstTest($testSuite);
if ($firstTest != null) {
if ($firstTest instanceof \PHPUnit\Event\Code\TestMethod) {
return $this->getTestMethodNameWithoutDatasetSuffix($firstTest);
}
}
@ -178,7 +178,7 @@ final readonly class Converter
public function getTestSuiteLocation(TestSuite $testSuite): ?string
{
$firstTest = $this->getFirstTest($testSuite);
if ($firstTest == null) {
if (! $firstTest instanceof \PHPUnit\Event\Code\TestMethod) {
return null;
}
$path = $firstTest->testDox()->prettifiedClassName();

View File

@ -5,6 +5,7 @@ declare(strict_types=1);
namespace Pest\PendingCalls;
use Closure;
use Pest\Concerns\Testable;
use Pest\Exceptions\InvalidArgumentException;
use Pest\Exceptions\TestDescriptionMissing;
use Pest\Factories\Attribute;
@ -25,9 +26,9 @@ use PHPUnit\Framework\TestCase;
/**
* @internal
*
* @mixin HigherOrderCallables|TestCase
* @mixin HigherOrderCallables|TestCase|Testable
*/
final class TestCall
final class TestCall // @phpstan-ignore-line
{
use Describable;

View File

@ -6,7 +6,7 @@ namespace Pest;
function version(): string
{
return '3.1.0';
return '3.4.0';
}
function testDirectory(string $file = ''): string

View File

@ -20,13 +20,13 @@ final class Closure
*/
public static function bind(?BaseClosure $closure, ?object $newThis, object|string|null $newScope = 'static'): BaseClosure
{
if ($closure == null) {
if (! $closure instanceof \Closure) {
throw ShouldNotHappen::fromMessage('Could not bind null closure.');
}
$closure = BaseClosure::bind($closure, $newThis, $newScope);
if ($closure == false) {
if (! $closure instanceof \Closure) {
throw ShouldNotHappen::fromMessage('Could not bind closure.');
}

View File

@ -1,5 +1,5 @@
Pest Testing Framework 3.1.0.
Pest Testing Framework 3.4.0.
USAGE: pest <file> [options]
@ -35,6 +35,7 @@
--exclude-group [name] ........... Exclude tests from the specified group(s)
--covers [name] ................. Only run tests that intend to cover [name]
--uses [name] ..................... Only run tests that intend to use [name]
--requires-php-extension [name] Only run tests that require PHP extension [name]
--list-test-files ................................ List available test files
--list-tests .......................................... List available tests
--list-tests-xml [file] ................. List available tests in XML format

View File

@ -1,3 +1,3 @@
Pest Testing Framework 3.1.0.
Pest Testing Framework 3.4.0.

View File

@ -968,6 +968,16 @@
✓ it can handle a non-defined exception
✓ it can handle a class not found Error
PASS Tests\Features\Expect\toUseStrictEquality
✓ missing strict equality
✓ has strict equality
✓ opposite missing strict equality
✓ opposite has strict equality
PASS Tests\Features\Expect\toUseStrictTypes
✓ pass
✓ failures
PASS Tests\Features\Expect\toUseTrait
✓ pass
✓ failures
@ -1574,4 +1584,4 @@
WARN Tests\Visual\Version
- visual snapshot of help command output
Tests: 2 deprecated, 4 warnings, 5 incomplete, 2 notices, 17 todos, 28 skipped, 1089 passed (2637 assertions)
Tests: 2 deprecated, 4 warnings, 5 incomplete, 2 notices, 17 todos, 28 skipped, 1095 passed (2648 assertions)

View File

@ -0,0 +1,21 @@
<?php
use Pest\Arch\Exceptions\ArchExpectationFailedException;
test('missing strict equality')
->throws(ArchExpectationFailedException::class)
->expect('Tests\\Fixtures\\Arch\\ToUseStrictEquality\\NotStrictEquality')
->toUseStrictEquality();
test('has strict equality')
->expect('Tests\\Fixtures\\Arch\\ToUseStrictEquality\\StrictEquality')
->toUseStrictEquality();
test('opposite missing strict equality')
->throws(ArchExpectationFailedException::class)
->expect('Tests\\Fixtures\\Arch\\ToUseStrictEquality\\StrictEquality')
->not->toUseStrictEquality();
test('opposite has strict equality')
->expect('Tests\\Fixtures\\Arch\\ToUseStrictEquality\\NotStrictEquality')
->not->toUseStrictEquality();

View File

@ -0,0 +1,17 @@
<?php
declare(strict_types=1);
use Pest\Arch\Exceptions\ArchExpectationFailedException;
use Tests\Fixtures\Arch\ToUseStrictTypes\HasNoStrictType;
use Tests\Fixtures\Arch\ToUseStrictTypes\HasStrictType;
use Tests\Fixtures\Arch\ToUseStrictTypes\HasStrictTypeWithCommentsAbove;
test('pass', function () {
expect(HasStrictType::class)->toUseStrictTypes()
->and(HasStrictTypeWithCommentsAbove::class)->toUseStrictTypes();
});
test('failures', function () {
expect(HasNoStrictType::class)->toUseStrictTypes();
})->throws(ArchExpectationFailedException::class);

View File

@ -0,0 +1,22 @@
<?php
declare(strict_types=1);
namespace Tests\Fixtures\Arch\ToUseStrictEquality;
class NotStrictEquality
{
public function test(): void
{
$a = 1;
$b = '1';
if ($a == $b) {
echo 'Equal';
}
if ($a != $b) {
echo 'Equal';
}
}
}

View File

@ -0,0 +1,22 @@
<?php
declare(strict_types=1);
namespace Tests\Fixtures\Arch\ToUseStrictEquality;
class StrictEquality
{
public function test(): void
{
$a = 1;
$b = '1';
if ($a === $b) {
echo 'Equal';
}
if ($a !== $b) {
echo 'Equal';
}
}
}

View File

@ -0,0 +1,5 @@
<?php
namespace Tests\Fixtures\Arch\ToUseStrictTypes;
class HasNoStrictType {}

View File

@ -0,0 +1,7 @@
<?php
declare(strict_types=1);
namespace Tests\Fixtures\Arch\ToUseStrictTypes;
class HasStrictType {}

View File

@ -0,0 +1,11 @@
<?php
/** @noinspection PhpUnused */
// some other comment
declare(strict_types=1);
namespace Tests\Fixtures\Arch\ToUseStrictTypes;
class HasStrictTypeWithCommentsAbove {}

View File

@ -16,7 +16,7 @@ $run = function () {
test('parallel', function () use ($run) {
expect($run('--exclude-group=integration'))
->toContain('Tests: 2 deprecated, 4 warnings, 5 incomplete, 2 notices, 17 todos, 19 skipped, 1079 passed (2613 assertions)')
->toContain('Tests: 2 deprecated, 4 warnings, 5 incomplete, 2 notices, 17 todos, 19 skipped, 1085 passed (2624 assertions)')
->toContain('Parallel: 3 processes');
})->skipOnWindows();