feat: basic PHPUnit 10 support

This commit is contained in:
Nuno Maduro
2021-10-24 01:03:18 +01:00
parent de46ee0f64
commit cf47b45262
32 changed files with 807 additions and 549 deletions

View File

@ -1,46 +0,0 @@
<?php
declare(strict_types=1);
namespace Pest\Actions;
use NunoMaduro\Collision\Adapters\Phpunit\Printer;
use Pest\Logging\JUnit;
use Pest\Logging\TeamCity;
use PHPUnit\TextUI\DefaultResultPrinter;
/**
* @internal
*/
final class AddsDefaults
{
private const PRINTER = 'printer';
/**
* Adds default arguments to the given `arguments` array.
*
* @param array<string, mixed> $arguments
*
* @return array<string, mixed>
*/
public static function to(array $arguments): array
{
if (!array_key_exists(self::PRINTER, $arguments)) {
$arguments[self::PRINTER] = new Printer(null, $arguments['verbose'] ?? false, $arguments['colors'] ?? DefaultResultPrinter::COLOR_ALWAYS);
}
if ($arguments[self::PRINTER] === \PHPUnit\Util\Log\TeamCity::class) {
$arguments[self::PRINTER] = new TeamCity(null, $arguments['verbose'] ?? false, $arguments['colors'] ?? DefaultResultPrinter::COLOR_ALWAYS);
}
// Load our junit logger instead.
if (array_key_exists('junitLogfile', $arguments)) {
$arguments['listeners'][] = new JUnit(
$arguments['junitLogfile']
);
unset($arguments['junitLogfile']);
}
return $arguments;
}
}

View File

@ -1,64 +0,0 @@
<?php
declare(strict_types=1);
namespace Pest\Actions;
use PHPUnit\Framework\TestCase;
use PHPUnit\Framework\TestSuite;
use PHPUnit\Framework\WarningTestCase;
/**
* @internal
*/
final class AddsTests
{
/**
* Adds tests to the given test suite.
*
* @param TestSuite<\PHPUnit\Framework\TestCase> $testSuite
*/
public static function to(TestSuite $testSuite, \Pest\TestSuite $pestTestSuite): void
{
self::removeTestClosureWarnings($testSuite);
$testSuites = [];
$pestTestSuite->tests->build($pestTestSuite, function (TestCase $testCase) use (&$testSuites): void {
$testCaseClass = get_class($testCase);
if (!array_key_exists($testCaseClass, $testSuites)) {
$testSuites[$testCaseClass] = [];
}
$testSuites[$testCaseClass][] = $testCase;
});
foreach ($testSuites as $testCaseName => $testCases) {
$testTestSuite = new TestSuite($testCaseName);
$testTestSuite->setTests([]);
foreach ($testCases as $testCase) {
$testTestSuite->addTest($testCase, $testCase->getGroups());
}
$testSuite->addTestSuite($testTestSuite);
}
}
/**
* @param TestSuite<\PHPUnit\Framework\TestCase> $testSuite
*/
private static function removeTestClosureWarnings(TestSuite $testSuite): void
{
$tests = $testSuite->tests();
foreach ($tests as $key => $test) {
if ($test instanceof TestSuite) {
self::removeTestClosureWarnings($test);
}
if ($test instanceof WarningTestCase) {
unset($tests[$key]);
}
}
$testSuite->setTests($tests);
}
}

View File

@ -1,38 +0,0 @@
<?php
declare(strict_types=1);
namespace Pest\Actions;
use Pest\Exceptions\AttributeNotSupportedYet;
use Pest\Exceptions\FileOrFolderNotFound;
use PHPUnit\TextUI\XmlConfiguration\Loader;
/**
* @internal
*/
final class ValidatesConfiguration
{
/**
* @var string
*/
private const CONFIGURATION_KEY = 'configuration';
/**
* Validates the configuration in the given `configuration`.
*
* @param array<string, mixed> $arguments
*/
public static function in($arguments): void
{
if (!array_key_exists(self::CONFIGURATION_KEY, $arguments) || !file_exists($arguments[self::CONFIGURATION_KEY])) {
throw new FileOrFolderNotFound('phpunit.xml');
}
$configuration = (new Loader())->load($arguments[self::CONFIGURATION_KEY])->phpunit();
if ($configuration->processIsolation()) {
throw new AttributeNotSupportedYet('processIsolation', 'true');
}
}
}

View File

@ -1,41 +0,0 @@
<?php
declare(strict_types=1);
namespace Pest\Actions;
use Pest\Exceptions\FileOrFolderNotFound;
use Pest\TestSuite;
/**
* @internal
*/
final class ValidatesEnvironment
{
/**
* The need files on the root path.
*
* @var array<int, string>
*/
private const NEEDED_FILES = [
'composer.json',
];
/**
* Validates the environment.
*/
public static function in(TestSuite $testSuite): void
{
$rootPath = $testSuite->rootPath;
$exists = function ($neededFile) use ($rootPath): bool {
return file_exists(sprintf('%s%s%s', $rootPath, DIRECTORY_SEPARATOR, $neededFile));
};
foreach (self::NEEDED_FILES as $neededFile) {
if (!$exists($neededFile)) {
throw new FileOrFolderNotFound($neededFile);
}
}
}
}

View File

@ -0,0 +1,29 @@
<?php
declare(strict_types=1);
namespace Pest\Bootstrappers;
use Pest\Emitters\DispatchingEmitter;
use PHPUnit\Event;
use ReflectionClass;
/**
* @internal
*/
final class BootEmitter
{
/**
* Boots the Event Emitter.
*/
public function __invoke(): void
{
if (!($baseEmitter = Event\Facade::emitter()) instanceof DispatchingEmitter) {
$reflectedClass = new ReflectionClass(Event\Facade::class);
$reflectedClass->setStaticPropertyValue('emitter', new DispatchingEmitter(
$baseEmitter,
));
}
}
}

View File

@ -0,0 +1,21 @@
<?php
declare(strict_types=1);
namespace Pest\Bootstrappers;
use NunoMaduro\Collision;
/**
* @internal
*/
final class BootExceptionHandler
{
/**
* Boots the Exception Handler.
*/
public function __invoke(): void
{
(new Collision\Provider())->register();
}
}

View File

@ -2,18 +2,18 @@
declare(strict_types=1);
namespace Pest\Actions;
namespace Pest\Bootstrappers;
use Pest\Support\Str;
use function Pest\testDirectory;
use PHPUnit\Util\FileLoader;
use Pest\TestSuite;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
/**
* @internal
*/
final class LoadStructure
final class BootFiles
{
/**
* The Pest convention.
@ -21,23 +21,23 @@ final class LoadStructure
* @var array<int, string>
*/
private const STRUCTURE = [
'Expectations.php',
'Datasets',
'Datasets.php',
'Expectations',
'Expectations.php',
'Helpers',
'Helpers.php',
'Pest.php',
'Datasets',
];
/**
* Validates the configuration in the given `configuration`.
* Boots the Subscribers.
*/
public static function in(string $rootPath): void
public function __invoke(): void
{
$testsPath = $rootPath . DIRECTORY_SEPARATOR . testDirectory();
$rootPath = TestSuite::getInstance()->rootPath;
$load = function ($filename): bool {
return file_exists($filename) && (bool) FileLoader::checkAndLoad($filename);
};
$testsPath = $rootPath . DIRECTORY_SEPARATOR . testDirectory();
foreach (self::STRUCTURE as $filename) {
$filename = sprintf('%s%s%s', $testsPath, DIRECTORY_SEPARATOR, $filename);
@ -50,14 +50,21 @@ final class LoadStructure
$directory = new RecursiveDirectoryIterator($filename);
$iterator = new RecursiveIteratorIterator($directory);
foreach ($iterator as $file) {
$filename = $file->__toString();
if (Str::endsWith($filename, '.php') && file_exists($filename)) {
require_once $filename;
}
$this->load($file->__toString());
}
} else {
$load($filename);
$this->load($filename);
}
}
}
/**
* Loads the given filename, if possible.
*/
private function load(string $filename): void
{
if (Str::endsWith($filename, '.php') && file_exists($filename)) {
include_once $filename;
}
}
}

View File

@ -0,0 +1,37 @@
<?php
declare(strict_types=1);
namespace Pest\Bootstrappers;
use Pest\Subscribers;
use PHPUnit\Event;
/**
* @internal
*/
final class BootSubscribers
{
/**
* The Kernel subscribers.
*
* @var array<int, class-string>
*/
private static array $subscribers = [
Subscribers\EnsureTestsAreLoaded::class,
Subscribers\EnsureConfigurationIsValid::class,
Subscribers\EnsureConfigurationDefaults::class,
];
/**
* Boots the Subscribers.
*/
public function __invoke(): void
{
foreach (self::$subscribers as $subscriber) {
Event\Facade::registerSubscriber(
new $subscriber()
);
}
}
}

View File

@ -5,6 +5,7 @@ declare(strict_types=1);
namespace Pest\Concerns;
use Closure;
use Pest\Support\Backtrace;
use Pest\Support\ChainableClosure;
use Pest\Support\ExceptionTrace;
use Pest\TestSuite;
@ -12,8 +13,7 @@ use PHPUnit\Framework\ExecutionOrderDependency;
use Throwable;
/**
* To avoid inheritance conflicts, all the fields related
* to Pest only will be prefixed by double underscore.
* To avoid inheritance conflicts, all the fields related to Pest only will be prefixed by double underscore.
*
* @internal
*/
@ -40,7 +40,7 @@ trait Testable
*
* @var Closure|null
*/
private $beforeEach = null;
private $__beforeEach = null;
/**
* Holds a global/shared afterEach ("tear down") closure if one has been
@ -48,7 +48,7 @@ trait Testable
*
* @var Closure|null
*/
private $afterEach = null;
private $__afterEach = null;
/**
* Holds a global/shared beforeAll ("set up before") closure if one has been
@ -56,7 +56,7 @@ trait Testable
*
* @var Closure|null
*/
private static $beforeAll = null;
private static $__beforeAll = null;
/**
* Holds a global/shared afterAll ("tear down after") closure if one has
@ -64,19 +64,21 @@ trait Testable
*
* @var Closure|null
*/
private static $afterAll = null;
private static $__afterAll = null;
/**
* Creates a new instance of the test case.
*/
public function __construct(Closure $test, string $description, array $data)
{
$this->__test = $test;
$this->__description = $description;
self::$beforeAll = null;
self::$afterAll = null;
$this->__test = $test;
$this->__description = $description;
self::$__beforeAll = null;
self::$__afterAll = null;
parent::__construct('__test', $data);
parent::__construct('__test');
$this->setData($description, $data);
}
/**
@ -84,7 +86,7 @@ trait Testable
*/
public function addGroups(array $groups): void
{
$groups = array_unique(array_merge($this->getGroups(), $groups));
$groups = array_unique(array_merge($this->groups(), $groups));
$this->setGroups($groups);
}
@ -101,7 +103,7 @@ trait Testable
$test = "{$className}::{$test}";
}
return new ExecutionOrderDependency($test, null, '');
return new ExecutionOrderDependency($test, '__test');
}, $tests);
$this->setDependencies($tests);
@ -111,14 +113,14 @@ trait Testable
* Add a shared/"global" before all test hook that will execute **before**
* the test defined `beforeAll` hook(s).
*/
public function addBeforeAll(?Closure $hook): void
public function __addBeforeAll(?Closure $hook): void
{
if (!$hook) {
return;
}
self::$beforeAll = (self::$beforeAll instanceof Closure)
? ChainableClosure::fromStatic(self::$beforeAll, $hook)
self::$__beforeAll = (self::$__beforeAll instanceof Closure)
? ChainableClosure::fromStatic(self::$__beforeAll, $hook)
: $hook;
}
@ -126,14 +128,14 @@ trait Testable
* Add a shared/"global" after all test hook that will execute **before**
* the test defined `afterAll` hook(s).
*/
public function addAfterAll(?Closure $hook): void
public function __addAfterAll(?Closure $hook): void
{
if (!$hook) {
return;
}
self::$afterAll = (self::$afterAll instanceof Closure)
? ChainableClosure::fromStatic(self::$afterAll, $hook)
self::$__afterAll = (self::$__afterAll instanceof Closure)
? ChainableClosure::fromStatic(self::$__afterAll, $hook)
: $hook;
}
@ -141,24 +143,24 @@ trait Testable
* Add a shared/"global" before each test hook that will execute **before**
* the test defined `beforeEach` hook.
*/
public function addBeforeEach(?Closure $hook): void
public function __addBeforeEach(?Closure $hook): void
{
$this->addHook('beforeEach', $hook);
$this->__addHook('__beforeEach', $hook);
}
/**
* Add a shared/"global" after each test hook that will execute **before**
* the test defined `afterEach` hook.
*/
public function addAfterEach(?Closure $hook): void
public function __addAfterEach(?Closure $hook): void
{
$this->addHook('afterEach', $hook);
$this->__addHook('__afterEach', $hook);
}
/**
* Add a shared/global hook and compose them if more than one is passed.
*/
private function addHook(string $property, ?Closure $hook): void
private function __addHook(string $property, ?Closure $hook): void
{
if (!$hook) {
return;
@ -176,7 +178,9 @@ trait Testable
*/
public function getName(bool $withDataSet = true): string
{
return $this->__description;
return (str_ends_with(Backtrace::file(), 'TestRunner.php') || Backtrace::line() === 277)
? '__test'
: $this->__description;
}
public static function __getFileName(): string
@ -193,8 +197,8 @@ trait Testable
$beforeAll = TestSuite::getInstance()->beforeAll->get(self::$__filename);
if (self::$beforeAll instanceof Closure) {
$beforeAll = ChainableClosure::fromStatic(self::$beforeAll, $beforeAll);
if (self::$__beforeAll instanceof Closure) {
$beforeAll = ChainableClosure::fromStatic(self::$__beforeAll, $beforeAll);
}
call_user_func(Closure::bind($beforeAll, null, self::class));
@ -207,8 +211,8 @@ trait Testable
{
$afterAll = TestSuite::getInstance()->afterAll->get(self::$__filename);
if (self::$afterAll instanceof Closure) {
$afterAll = ChainableClosure::fromStatic(self::$afterAll, $afterAll);
if (self::$__afterAll instanceof Closure) {
$afterAll = ChainableClosure::fromStatic(self::$__afterAll, $afterAll);
}
call_user_func(Closure::bind($afterAll, null, self::class));
@ -227,8 +231,8 @@ trait Testable
$beforeEach = TestSuite::getInstance()->beforeEach->get(self::$__filename);
if ($this->beforeEach instanceof Closure) {
$beforeEach = ChainableClosure::from($this->beforeEach, $beforeEach);
if ($this->__beforeEach instanceof Closure) {
$beforeEach = ChainableClosure::from($this->__beforeEach, $beforeEach);
}
$this->__callClosure($beforeEach, func_get_args());
@ -241,8 +245,8 @@ trait Testable
{
$afterEach = TestSuite::getInstance()->afterEach->get(self::$__filename);
if ($this->afterEach instanceof Closure) {
$afterEach = ChainableClosure::from($this->afterEach, $afterEach);
if ($this->__afterEach instanceof Closure) {
$afterEach = ChainableClosure::from($this->__afterEach, $afterEach);
}
$this->__callClosure($afterEach, func_get_args());
@ -273,7 +277,7 @@ trait Testable
*/
public function __test()
{
return $this->__callClosure($this->__test, $this->resolveTestArguments(func_get_args()));
return $this->__callClosure($this->__test, $this->__resolveTestArguments(func_get_args()));
}
/**
@ -281,7 +285,7 @@ trait Testable
*
* @throws Throwable
*/
private function resolveTestArguments(array $arguments): array
private function __resolveTestArguments(array $arguments): array
{
return array_map(function ($data) {
return $data instanceof Closure ? $this->__callClosure($data, []) : $data;

View File

@ -1,132 +0,0 @@
<?php
declare(strict_types=1);
namespace Pest\Console;
use Pest\Actions\AddsDefaults;
use Pest\Actions\AddsTests;
use Pest\Actions\InteractsWithPlugins;
use Pest\Actions\LoadStructure;
use Pest\Actions\ValidatesConfiguration;
use Pest\Plugins\Version;
use Pest\Support\Container;
use Pest\TestSuite;
use PHPUnit\Framework\TestSuite as BaseTestSuite;
use PHPUnit\TextUI\Command as BaseCommand;
use PHPUnit\TextUI\TestRunner;
use SebastianBergmann\FileIterator\Facade as FileIteratorFacade;
use Symfony\Component\Console\Output\OutputInterface;
/**
* @internal
*/
final class Command extends BaseCommand
{
/**
* Holds the current testing suite.
*
* @var TestSuite
*/
private $testSuite;
/**
* Holds the current console output.
*
* @var OutputInterface
*/
private $output;
/**
* Creates a new instance of the command class.
*/
public function __construct(TestSuite $testSuite, OutputInterface $output)
{
$this->testSuite = $testSuite;
$this->output = $output;
}
/**
* {@inheritdoc}
*
* @phpstan-ignore-next-line
*
* @param array<int, string> $argv
*/
protected function handleArguments(array $argv): void
{
$argv = InteractsWithPlugins::handleArguments($argv);
parent::handleArguments($argv);
/*
* Let's validate the configuration. Making
* sure all options are yet supported by Pest.
*/
ValidatesConfiguration::in($this->arguments);
}
/**
* Creates a new PHPUnit test runner.
*/
protected function createRunner(): TestRunner
{
/*
* First, let's add the defaults we use on `pest`. Those
* are the printer class, and others that may be appear.
*/
$this->arguments = AddsDefaults::to($this->arguments);
$testRunner = new TestRunner($this->arguments['loader']);
$testSuite = $this->arguments['test'];
if (is_string($testSuite)) {
if (\is_dir($testSuite)) {
/** @var string[] $files */
$files = (new FileIteratorFacade())->getFilesAsArray(
$testSuite,
$this->arguments['testSuffixes']
);
} else {
$files = [$testSuite];
}
$testSuite = new BaseTestSuite($testSuite);
$testSuite->addTestFiles($files);
$this->arguments['test'] = $testSuite;
}
AddsTests::to($testSuite, $this->testSuite);
return $testRunner;
}
/**
* {@inheritdoc}
*
* @phpstan-ignore-next-line
*
* @param array<int, string> $argv
*/
public function run(array $argv, bool $exit = true): int
{
LoadStructure::in($this->testSuite->rootPath);
$result = parent::run($argv, false);
$result = InteractsWithPlugins::addOutput($result);
exit($result);
}
protected function showHelp(): void
{
/** @var Version $version */
$version = Container::getInstance()->get(Version::class);
$version->handleArguments(['--version']);
parent::showHelp();
(new Help($this->output))();
}
}

72
src/Console/Kernel.php Normal file
View File

@ -0,0 +1,72 @@
<?php
declare(strict_types=1);
namespace Pest\Console;
use Pest\Actions\InteractsWithPlugins;
use Pest\Bootstrappers;
use PHPUnit\TextUI\Application;
/**
* @internal
*/
final class Kernel
{
/**
* The Kernel bootstrappers.
*
* @var array<int, class-string>
*/
private static array $bootstrappers = [
Bootstrappers\BootExceptionHandler::class,
Bootstrappers\BootEmitter::class,
Bootstrappers\BootSubscribers::class,
Bootstrappers\BootFiles::class,
];
/**
* Creates a new Kernel instance.
*/
public function __construct(
private Application $application
) {
// ..
}
/**
* Boots the Kernel.
*/
public static function boot(): self
{
foreach (self::$bootstrappers as $bootstrapper) {
(new $bootstrapper())->__invoke();
}
return new self(new Application());
}
/**
* Handles the given argv.
*
* @param array<int, string> $argv
*/
public function handle(array $argv): int
{
$argv = InteractsWithPlugins::handleArguments($argv);
$result = $this->application->run(
$argv, false,
);
return InteractsWithPlugins::addOutput($result);
}
/**
* Shutdown the Kernel.
*/
public function shutdown(): void
{
// TODO
}
}

View File

@ -0,0 +1,248 @@
<?php
declare(strict_types=1);
namespace Pest\Emitters;
use Pest\Subscribers\EnsureTestsAreLoaded;
use PHPUnit\Event\Code;
use PHPUnit\Event\Code\Throwable;
use PHPUnit\Event\Emitter;
use PHPUnit\Framework\Constraint;
use PHPUnit\Framework\TestResult;
use PHPUnit\Framework\TestSuite;
use PHPUnit\TextUI\Configuration\Configuration;
use SebastianBergmann\GlobalState\Snapshot;
/**
* @internal
*/
final class DispatchingEmitter implements Emitter
{
public function __construct(private Emitter $baseEmitter)
{
// ..
}
public function eventFacadeSealed(): void
{
$this->baseEmitter->eventFacadeSealed(...func_get_args());
}
public function testRunnerStarted(): void
{
$this->baseEmitter->testRunnerStarted(...func_get_args());
}
public function testRunnerConfigured(Configuration $configuration): void
{
$this->baseEmitter->testRunnerConfigured($configuration);
}
public function testRunnerFinished(): void
{
$this->baseEmitter->testRunnerFinished(...func_get_args());
}
public function assertionMade(mixed $value, Constraint\Constraint $constraint, string $message, bool $hasFailed): void
{
$this->baseEmitter->assertionMade($value, $constraint, $message, $hasFailed);
}
public function bootstrapFinished(string $filename): void
{
$this->baseEmitter->bootstrapFinished($filename);
}
public function comparatorRegistered(string $className): void
{
$this->baseEmitter->comparatorRegistered($className);
}
public function extensionLoaded(string $name, string $version): void
{
$this->baseEmitter->extensionLoaded($name, $version);
}
public function globalStateCaptured(Snapshot $snapshot): void
{
$this->baseEmitter->globalStateCaptured($snapshot);
}
public function globalStateModified(Snapshot $snapshotBefore, Snapshot $snapshotAfter, string $diff): void
{
$this->baseEmitter->globalStateModified($snapshotBefore, $snapshotAfter, $diff);
}
public function globalStateRestored(Snapshot $snapshot): void
{
$this->baseEmitter->globalStateRestored($snapshot);
}
public function testErrored(Code\Test $test, Throwable $throwable): void
{
$this->baseEmitter->testErrored(...func_get_args());
}
public function testFailed(Code\Test $test, Throwable $throwable): void
{
$this->baseEmitter->testFailed(...func_get_args());
}
public function testFinished(Code\Test $test): void
{
$this->baseEmitter->testFinished(...func_get_args());
}
public function testOutputPrinted(Code\Test $test, string $output): void
{
$this->baseEmitter->testOutputPrinted(...func_get_args());
}
public function testPassed(Code\Test $test): void
{
$this->baseEmitter->testPassed(...func_get_args());
}
public function testPassedWithWarning(Code\Test $test, Throwable $throwable): void
{
$this->baseEmitter->testPassedWithWarning(...func_get_args());
}
public function testConsideredRisky(Code\Test $test, Throwable $throwable): void
{
$this->baseEmitter->testConsideredRisky(...func_get_args());
}
public function testAborted(Code\Test $test, Throwable $throwable): void
{
$this->baseEmitter->testAborted(...func_get_args());
}
public function testSkipped(Code\Test $test, string $message): void
{
$this->baseEmitter->testSkipped(...func_get_args());
}
public function testPrepared(Code\Test $test): void
{
$this->baseEmitter->testPrepared(...func_get_args());
}
public function testAfterTestMethodFinished(string $testClassName, Code\ClassMethod ...$calledMethods): void
{
$this->baseEmitter->testAfterTestMethodFinished(...func_get_args());
}
public function testAfterLastTestMethodFinished(string $testClassName, Code\ClassMethod ...$calledMethods): void
{
$this->baseEmitter->testAfterLastTestMethodFinished(...func_get_args());
}
public function testBeforeFirstTestMethodCalled(string $testClassName, Code\ClassMethod $calledMethod): void
{
$this->baseEmitter->testBeforeFirstTestMethodCalled(...func_get_args());
}
public function testBeforeFirstTestMethodFinished(string $testClassName, Code\ClassMethod ...$calledMethods): void
{
$this->baseEmitter->testBeforeFirstTestMethodFinished(...func_get_args());
}
public function testBeforeTestMethodCalled(string $testClassName, Code\ClassMethod $calledMethod): void
{
$this->baseEmitter->testBeforeTestMethodCalled(...func_get_args());
}
public function testBeforeTestMethodFinished(string $testClassName, Code\ClassMethod ...$calledMethods): void
{
$this->baseEmitter->testBeforeTestMethodFinished(...func_get_args());
}
public function testPreConditionCalled(string $testClassName, Code\ClassMethod $calledMethod): void
{
$this->baseEmitter->testPreConditionCalled(...func_get_args());
}
public function testPreConditionFinished(string $testClassName, Code\ClassMethod ...$calledMethods): void
{
$this->baseEmitter->testPreConditionFinished(...func_get_args());
}
public function testPostConditionCalled(string $testClassName, Code\ClassMethod $calledMethod): void
{
$this->baseEmitter->testPostConditionCalled(...func_get_args());
}
public function testPostConditionFinished(string $testClassName, Code\ClassMethod ...$calledMethods): void
{
$this->baseEmitter->testPostConditionFinished(...func_get_args());
}
public function testAfterTestMethodCalled(string $testClassName, Code\ClassMethod $calledMethod): void
{
$this->baseEmitter->testAfterTestMethodCalled(...func_get_args());
}
public function testAfterLastTestMethodCalled(string $testClassName, Code\ClassMethod $calledMethod): void
{
$this->baseEmitter->testAfterLastTestMethodCalled(...func_get_args());
}
public function testMockObjectCreated(string $className): void
{
$this->baseEmitter->testMockObjectCreated(...func_get_args());
}
public function testMockObjectCreatedForTrait(string $traitName): void
{
$this->baseEmitter->testMockObjectCreatedForTrait(...func_get_args());
}
public function testMockObjectCreatedForAbstractClass(string $className): void
{
$this->baseEmitter->testMockObjectCreatedForAbstractClass(...func_get_args());
}
public function testMockObjectCreatedFromWsdl(string $wsdlFile, string $originalClassName, string $mockClassName, array $methods, bool $callOriginalConstructor, array $options): void
{
$this->baseEmitter->testMockObjectCreatedFromWsdl(...func_get_args());
}
public function testPartialMockObjectCreated(string $className, string ...$methodNames): void
{
$this->baseEmitter->testPartialMockObjectCreated(...func_get_args());
}
public function testTestProxyCreated(string $className, array $constructorArguments): void
{
$this->baseEmitter->testTestProxyCreated(...func_get_args());
}
public function testTestStubCreated(string $className): void
{
$this->baseEmitter->testTestStubCreated(...func_get_args());
}
public function testSuiteLoaded(TestSuite $testSuite): void
{
EnsureTestsAreLoaded::setTestSuite($testSuite);
$this->baseEmitter->testSuiteLoaded(...func_get_args());
}
public function testSuiteSorted(int $executionOrder, int $executionOrderDefects, bool $resolveDependencies): void
{
$this->baseEmitter->testSuiteSorted(...func_get_args());
}
public function testSuiteStarted(TestSuite $testSuite): void
{
$this->baseEmitter->testSuiteStarted(...func_get_args());
}
public function testSuiteFinished(TestSuite $testSuite, TestResult $result): void
{
$this->baseEmitter->testSuiteFinished(...func_get_args());
}
}

View File

@ -92,16 +92,14 @@ final class TestCaseFactory
public $factoryProxies;
/**
* Holds the higher order
* messages that are proxyble.
* Holds the higher order messages that are proxyble.
*
* @var HigherOrderMessageCollection
*/
public $proxies;
/**
* Holds the higher order
* messages that are chainable.
* Holds the higher order messages that are chainable.
*
* @var HigherOrderMessageCollection
*/
@ -232,7 +230,7 @@ final class TestCaseFactory
/**
* Determine if the test case will receive argument input from Pest, or not.
*/
public function receivesArguments(): bool
public function __receivesArguments(): bool
{
return count($this->datasets) > 0
|| $this->factoryProxies->count('addDependencies') > 0;

View File

@ -41,6 +41,7 @@ final class AfterEachRepository
return ChainableClosure::from(function (): void {
if (class_exists(Mockery::class)) {
/* @phpstan-ignore-next-line */
if ($container = Mockery::getContainer()) {
/* @phpstan-ignore-next-line */
$this->addToAssertionCount($container->mockery_getExpectationCount());

View File

@ -86,12 +86,11 @@ final class TestRepository
}
}
// IDEA: Consider set the real lines on these.
$testCase->factoryProxies->add($filename, 0, 'addGroups', [$groups]);
$testCase->factoryProxies->add($filename, 0, 'addBeforeAll', [$hooks[0] ?? null]);
$testCase->factoryProxies->add($filename, 0, 'addBeforeEach', [$hooks[1] ?? null]);
$testCase->factoryProxies->add($filename, 0, 'addAfterEach', [$hooks[2] ?? null]);
$testCase->factoryProxies->add($filename, 0, 'addAfterAll', [$hooks[3] ?? null]);
$testCase->factoryProxies->add($filename, 0, '__addBeforeAll', [$hooks[0] ?? null]);
$testCase->factoryProxies->add($filename, 0, '__addBeforeEach', [$hooks[1] ?? null]);
$testCase->factoryProxies->add($filename, 0, '__addAfterEach', [$hooks[2] ?? null]);
$testCase->factoryProxies->add($filename, 0, '__addAfterAll', [$hooks[3] ?? null]);
}
};
@ -171,7 +170,7 @@ final class TestRepository
throw new TestAlreadyExist($test->filename, $test->description);
}
if (!$test->receivesArguments()) {
if (!$test->__receivesArguments()) {
$arguments = Reflection::getFunctionArguments($test->test);
if (count($arguments) > 0) {

View File

@ -0,0 +1,22 @@
<?php
declare(strict_types=1);
namespace Pest\Subscribers;
use PHPUnit\Event\TestRunner\Configured;
use PHPUnit\Event\TestRunner\ConfiguredSubscriber;
/**
* @internal
*/
final class EnsureConfigurationDefaults implements ConfiguredSubscriber
{
/**
* Runs the subscriber.
*/
public function notify(Configured $event): void
{
$configuration = $event->configuration();
}
}

View File

@ -0,0 +1,27 @@
<?php
declare(strict_types=1);
namespace Pest\Subscribers;
use Pest\Exceptions\AttributeNotSupportedYet;
use PHPUnit\Event\TestRunner\Configured;
use PHPUnit\Event\TestRunner\ConfiguredSubscriber;
/**
* @internal
*/
final class EnsureConfigurationIsValid implements ConfiguredSubscriber
{
/**
* Runs the subscriber.
*/
public function notify(Configured $event): void
{
$configuration = $event->configuration();
if ($configuration->processIsolation()) {
throw new AttributeNotSupportedYet('processIsolation', 'true');
}
}
}

View File

@ -0,0 +1,79 @@
<?php
declare(strict_types=1);
namespace Pest\Subscribers;
use PHPUnit\Event\TestSuite\Loaded;
use PHPUnit\Event\TestSuite\LoadedSubscriber;
use PHPUnit\Framework\TestCase;
use PHPUnit\Framework\TestSuite;
use PHPUnit\Framework\WarningTestCase;
/**
* @internal
*/
final class EnsureTestsAreLoaded implements LoadedSubscriber
{
/**
* The current test suite, if any.
*/
private static ?TestSuite $testSuite;
/**
* Runs the subscriber.
*/
public function notify(Loaded $event): void
{
$this->removeWarnings(self::$testSuite);
$testSuites = [];
$testSuite = \Pest\TestSuite::getInstance();
$testSuite->tests->build($testSuite, function (TestCase $testCase) use (&$testSuites): void {
$testCaseClass = get_class($testCase);
if (!array_key_exists($testCaseClass, $testSuites)) {
$testSuites[$testCaseClass] = [];
}
$testSuites[$testCaseClass][] = $testCase;
});
foreach ($testSuites as $testCaseName => $testCases) {
$testTestSuite = new TestSuite($testCaseName);
$testTestSuite->setTests([]);
foreach ($testCases as $testCase) {
$testTestSuite->addTest($testCase, $testCase->groups());
}
self::$testSuite->addTestSuite($testTestSuite);
}
}
/**
* Sets the current test suite.
*/
public static function setTestSuite(TestSuite $testSuite): void
{
self::$testSuite = $testSuite;
}
/**
* Removes the test case that have "empty" warnings.
*/
private function removeWarnings(TestSuite $testSuite): void
{
$tests = $testSuite->tests();
foreach ($tests as $key => $test) {
if ($test instanceof TestSuite) {
$this->removeWarnings($test);
}
if ($test instanceof WarningTestCase) {
unset($tests[$key]);
}
}
$testSuite->setTests(array_values($tests));
}
}

View File

@ -26,7 +26,7 @@ final class Backtrace
$current = null;
foreach (debug_backtrace(self::BACKTRACE_OPTIONS) as $trace) {
if (Str::endsWith($trace[self::FILE], (string) realpath('vendor/phpunit/phpunit/src/Util/FileLoader.php'))) {
if (Str::endsWith($trace[self::FILE], (string) realpath('overrides/Runner/TestSuiteLoader.php'))) {
break;
}