feat: reworks evalution of Test Case

This commit is contained in:
Nuno Maduro
2021-11-14 19:58:25 +00:00
parent cd34f0ba81
commit 4b213d63bd
26 changed files with 603 additions and 620 deletions

View File

@ -5,16 +5,11 @@ declare(strict_types=1);
namespace Pest\Repositories;
use Closure;
use Pest\Exceptions\DatasetMissing;
use Pest\Exceptions\ShouldNotHappen;
use Pest\Exceptions\TestAlreadyExist;
use Pest\Exceptions\TestCaseAlreadyInUse;
use Pest\Exceptions\TestCaseClassOrTraitNotFound;
use Pest\Factories\TestCaseFactory;
use Pest\Plugins\Environment;
use Pest\Support\Reflection;
use Pest\Factories\TestCaseMethodFactory;
use Pest\Support\Str;
use Pest\TestSuite;
use PHPUnit\Framework\TestCase;
/**
@ -22,15 +17,10 @@ use PHPUnit\Framework\TestCase;
*/
final class TestRepository
{
/**
* @var non-empty-string
*/
private const SEPARATOR = '>>>';
/**
* @var array<string, TestCaseFactory>
*/
private array $state = [];
private array $testCases = [];
/**
* @var array<string, array<int, array<int, string|Closure>>>
@ -42,7 +32,7 @@ final class TestRepository
*/
public function count(): int
{
return count($this->state);
return count($this->testCases);
}
/**
@ -52,74 +42,13 @@ final class TestRepository
*/
public function getFilenames(): array
{
$testsWithOnly = $this->testsUsingOnly();
$testCases = array_filter($this->testCases, static fn (TestCaseFactory $testCase) => count($testCase->methodsUsingOnly()) > 0);
return array_values(array_map(fn (TestCaseFactory $factory): string => $factory->filename, count($testsWithOnly) > 0 ? $testsWithOnly : $this->state));
}
/**
* Calls the given callable foreach test case.
*/
public function build(TestSuite $testSuite, callable $each): void
{
$startsWith = fn (string $target, string $directory): bool => Str::startsWith($target, $directory . DIRECTORY_SEPARATOR);
foreach ($this->uses as $path => $uses) {
[$classOrTraits, $groups, $hooks] = $uses;
$setClassName = function (TestCaseFactory $testCase, string $key) use ($path, $classOrTraits, $groups, $startsWith, $hooks): void {
[$filename] = explode(self::SEPARATOR, $key);
if ((!is_dir($path) && $filename === $path) || (is_dir($path) && $startsWith($filename, $path))) {
foreach ($classOrTraits as $class) { /** @var string $class */
if (class_exists($class)) {
if ($testCase->class !== TestCase::class) {
throw new TestCaseAlreadyInUse($testCase->class, $class, $filename);
}
$testCase->class = $class;
} elseif (trait_exists($class)) {
$testCase->traits[] = $class;
}
}
$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]);
}
};
foreach ($this->state as $key => $test) {
$setClassName($test, $key);
}
if (count($testCases) === 0) {
$testCases = $this->testCases;
}
$onlyState = $this->testsUsingOnly();
$state = count($onlyState) > 0 ? $onlyState : $this->state;
foreach ($state as $testFactory) {
/** @var TestCaseFactory $testFactory */
$tests = $testFactory->make($testSuite);
foreach ($tests as $test) {
$each($test);
}
}
}
/**
* Return all tests that have called the only method.
*
* @return array<TestCaseFactory>
*/
private function testsUsingOnly(): array
{
if (Environment::name() === Environment::CI) {
return [];
}
return array_filter($this->state, fn ($testFactory): bool => $testFactory->only);
return array_values(array_map(static fn (TestCaseFactory $factory): string => $factory->filename, $testCases));
}
/**
@ -151,27 +80,73 @@ final class TestRepository
}
}
/**
* Sets a test case by the given filename and description.
*/
public function set(TestCaseFactory $test): void
public function get($filename): TestCaseFactory
{
if ($test->description === null) {
throw ShouldNotHappen::fromMessage('Trying to create a test without description.');
return $this->testCases[$filename];
}
/**
* Sets a new test case method.
*/
public function set(TestCaseMethodFactory $method): void
{
if (!isset($this->testCases[$method->filename])) {
$this->testCases[$method->filename] = new TestCaseFactory($method->filename);
}
if (array_key_exists(sprintf('%s%s%s', $test->filename, self::SEPARATOR, $test->description), $this->state)) {
throw new TestAlreadyExist($test->filename, $test->description);
$this->testCases[$method->filename]->addMethod($method);
}
/**
* Makes a Test Case from the given filename, if exists.
*/
public function makeIfExists(string $filename): void
{
if (isset($this->testCases[$filename])) {
$this->make($this->testCases[$filename]);
}
}
if (!$test->__receivesArguments()) {
$arguments = Reflection::getFunctionArguments($test->test);
/**
* Makes a Test Case using the given factory.
*/
private function make(TestCaseFactory $testCase): void
{
$startsWith = static fn (string $target, string $directory): bool => Str::startsWith($target, $directory . DIRECTORY_SEPARATOR);
if (count($arguments) > 0) {
throw new DatasetMissing($test->filename, $test->description, $arguments);
foreach ($this->uses as $path => $uses) {
[$classOrTraits, $groups, $hooks] = $uses;
if ((!is_dir($path) && $testCase->filename === $path) || (is_dir($path) && $startsWith($testCase->filename, $path))) {
foreach ($classOrTraits as $class) {
/** @var string $class */
if (class_exists($class)) {
if ($testCase->class !== TestCase::class) {
throw new TestCaseAlreadyInUse($testCase->class, $class, $testCase->filename);
}
$testCase->class = $class;
} elseif (trait_exists($class)) {
$testCase->traits[] = $class;
}
}
foreach ($testCase->methods as $method) {
foreach ($groups as $group) {
$method->groups[] = $group;
}
}
foreach ($testCase->methods as $method) {
$method->groups = array_merge($groups, $method->groups);
}
$testCase->factoryProxies->add($testCase->filename, 0, '__addBeforeAll', [$hooks[0] ?? null]);
$testCase->factoryProxies->add($testCase->filename, 0, '__addBeforeEach', [$hooks[1] ?? null]);
$testCase->factoryProxies->add($testCase->filename, 0, '__addAfterEach', [$hooks[2] ?? null]);
$testCase->factoryProxies->add($testCase->filename, 0, '__addAfterAll', [$hooks[3] ?? null]);
}
}
$this->state[sprintf('%s%s%s', $test->filename, self::SEPARATOR, $test->description)] = $test;
$testCase->make();
}
}