Merge branch '2.x' into 3.x

This commit is contained in:
Nuno Maduro
2024-08-22 21:21:52 +01:00
10 changed files with 75 additions and 1588 deletions

View File

@ -72,7 +72,7 @@
"test:refacto": "rector --dry-run", "test:refacto": "rector --dry-run",
"test:lint": "pint --test", "test:lint": "pint --test",
"test:type:check": "phpstan analyse --ansi --memory-limit=-1 --debug", "test:type:check": "phpstan analyse --ansi --memory-limit=-1 --debug",
"test:type:coverage": "php bin/pest --type-coverage --min=100", "test:type:coverage": "php -d memory_limit=-1 bin/pest --type-coverage --min=100",
"test:unit": "php bin/pest --colors=always --exclude-group=integration --compact", "test:unit": "php bin/pest --colors=always --exclude-group=integration --compact",
"test:inline": "php bin/pest --colors=always --configuration=phpunit.inline.xml", "test:inline": "php bin/pest --colors=always --configuration=phpunit.inline.xml",
"test:parallel": "php bin/pest --colors=always --exclude-group=integration --parallel --processes=3", "test:parallel": "php bin/pest --colors=always --exclude-group=integration --parallel --processes=3",

View File

@ -291,12 +291,14 @@ trait Testable
$afterEach = ChainableClosure::bound($this->__afterEach, $afterEach); $afterEach = ChainableClosure::bound($this->__afterEach, $afterEach);
} }
$this->__callClosure($afterEach, $arguments); try {
$this->__callClosure($afterEach, func_get_args());
} finally {
parent::tearDown(); parent::tearDown();
TestSuite::getInstance()->test = null; TestSuite::getInstance()->test = null;
} }
}
/** /**
* Executes the Test Case current test. * Executes the Test Case current test.

View File

@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
namespace Pest\Exceptions;
use InvalidArgumentException;
use NunoMaduro\Collision\Contracts\RenderlessEditor;
use NunoMaduro\Collision\Contracts\RenderlessTrace;
use Pest\Factories\TestCaseMethodFactory;
use Symfony\Component\Console\Exception\ExceptionInterface;
/**
* @internal
*/
final class TestClosureMustNotBeStatic extends InvalidArgumentException implements ExceptionInterface, RenderlessEditor, RenderlessTrace
{
/**
* Creates a new Exception instance.
*/
public function __construct(TestCaseMethodFactory $method)
{
parent::__construct(
sprintf(
'Test closure must not be static. Please remove the `static` keyword from the `%s` method in `%s`.',
$method->description,
$method->filename
)
);
}
}

View File

@ -509,7 +509,7 @@ final class Expectation
{ {
return Targeted::make( return Targeted::make(
$this, $this,
fn (ObjectDescription $object): bool => str_contains((string) file_get_contents($object->path), 'declare(strict_types=1);'), fn (ObjectDescription $object): bool => (bool) preg_match('/^<\?php\s+declare\(.*?strict_types\s?=\s?1.*?\);/', (string) file_get_contents($object->path)),
'to use strict types', 'to use strict types',
FileLineFinder::where(fn (string $line): bool => str_contains($line, '<?php')), FileLineFinder::where(fn (string $line): bool => str_contains($line, '<?php')),
); );

View File

@ -146,7 +146,7 @@ final class OppositeExpectation
{ {
return Targeted::make( return Targeted::make(
$this->original, $this->original,
fn (ObjectDescription $object): bool => ! str_contains((string) file_get_contents($object->path), 'declare(strict_types=1);'), fn (ObjectDescription $object): bool => ! (bool) preg_match('/^<\?php\s+declare\(.*?strict_types\s?=\s?1.*?\);/', (string) file_get_contents($object->path)),
'not to use strict types', 'not to use strict types',
FileLineFinder::where(fn (string $line): bool => str_contains($line, '<?php')), FileLineFinder::where(fn (string $line): bool => str_contains($line, '<?php')),
); );

View File

@ -11,6 +11,7 @@ use Pest\Evaluators\Attributes;
use Pest\Exceptions\DatasetMissing; use Pest\Exceptions\DatasetMissing;
use Pest\Exceptions\ShouldNotHappen; use Pest\Exceptions\ShouldNotHappen;
use Pest\Exceptions\TestAlreadyExist; use Pest\Exceptions\TestAlreadyExist;
use Pest\Exceptions\TestClosureMustNotBeStatic;
use Pest\Exceptions\TestDescriptionMissing; use Pest\Exceptions\TestDescriptionMissing;
use Pest\Factories\Concerns\HigherOrderable; use Pest\Factories\Concerns\HigherOrderable;
use Pest\Support\Reflection; use Pest\Support\Reflection;
@ -188,6 +189,14 @@ final class TestCaseFactory
throw new TestAlreadyExist($method->filename, $method->description); throw new TestAlreadyExist($method->filename, $method->description);
} }
if (
$method->closure instanceof \Closure &&
(new \ReflectionFunction($method->closure))->isStatic()
) {
throw new TestClosureMustNotBeStatic($method);
}
if (! $method->receivesArguments()) { if (! $method->receivesArguments()) {
if (! $method->closure instanceof \Closure) { if (! $method->closure instanceof \Closure) {
throw ShouldNotHappen::fromMessage('The test closure may not be empty.'); throw ShouldNotHappen::fromMessage('The test closure may not be empty.');

View File

@ -40,10 +40,21 @@ final class Result
*/ */
public static function exitCode(Configuration $configuration, TestResult $result): int public static function exitCode(Configuration $configuration, TestResult $result): int
{ {
if ($result->wasSuccessfulIgnoringPhpunitWarnings() if ($result->wasSuccessfulIgnoringPhpunitWarnings()) {
&& ! $result->hasTestTriggeredPhpunitWarningEvents()) { if ($configuration->failOnWarning()) {
$warnings = $result->numberOfTestsWithTestTriggeredPhpunitWarningEvents()
+ count($result->warnings())
+ count($result->phpWarnings());
if ($warnings > 0) {
return self::FAILURE_EXIT;
}
}
if (! $result->hasTestTriggeredPhpunitWarningEvents()) {
return self::SUCCESS_EXIT; return self::SUCCESS_EXIT;
} }
}
if ($configuration->failOnEmptyTestSuite() && ResultReflection::numberOfTests($result) === 0) { if ($configuration->failOnEmptyTestSuite() && ResultReflection::numberOfTests($result) === 0) {
return self::FAILURE_EXIT; return self::FAILURE_EXIT;
@ -54,14 +65,6 @@ final class Result
$returnCode = self::FAILURE_EXIT; $returnCode = self::FAILURE_EXIT;
} }
$warnings = $result->numberOfTestsWithTestTriggeredPhpunitWarningEvents()
+ count($result->warnings())
+ count($result->phpWarnings());
if ($configuration->failOnWarning() && $warnings > 0) {
$returnCode = self::FAILURE_EXIT;
}
if ($configuration->failOnIncomplete() && $result->hasTestMarkedIncompleteEvents()) { if ($configuration->failOnIncomplete() && $result->hasTestMarkedIncompleteEvents()) {
$returnCode = self::FAILURE_EXIT; $returnCode = self::FAILURE_EXIT;
} }

File diff suppressed because it is too large Load Diff

View File

@ -2,6 +2,7 @@
use Pest\Exceptions\DatasetMissing; use Pest\Exceptions\DatasetMissing;
use Pest\Exceptions\TestAlreadyExist; use Pest\Exceptions\TestAlreadyExist;
use Pest\Exceptions\TestClosureMustNotBeStatic;
use Pest\Factories\TestCaseMethodFactory; use Pest\Factories\TestCaseMethodFactory;
use Pest\TestSuite; use Pest\TestSuite;
@ -17,6 +18,16 @@ it('does not allow to add the same test description twice', function () {
sprintf('A test with the description `%s` already exists in the filename `%s`.', 'bar', 'foo'), sprintf('A test with the description `%s` already exists in the filename `%s`.', 'bar', 'foo'),
); );
it('does not allow static closures', function () {
$testSuite = new TestSuite(getcwd(), 'tests');
$method = new TestCaseMethodFactory('foo', 'bar', static function () {});
$testSuite->tests->set($method);
})->throws(
TestClosureMustNotBeStatic::class,
'Test closure must not be static. Please remove the `static` keyword from the `bar` method in `foo`.',
);
it('alerts users about tests with arguments but no input', function () { it('alerts users about tests with arguments but no input', function () {
$testSuite = new TestSuite(getcwd(), 'tests'); $testSuite = new TestSuite(getcwd(), 'tests');

View File

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