mirror of
https://github.com/pestphp/pest.git
synced 2026-03-06 07:47:22 +01:00
Merge branch 'master' of https://github.com/pestphp/pest into feat-teamcity
Conflicts: phpstan.neon
This commit is contained in:
@ -14,5 +14,5 @@ trim_trailing_whitespace = true
|
|||||||
[*.md]
|
[*.md]
|
||||||
trim_trailing_whitespace = false
|
trim_trailing_whitespace = false
|
||||||
|
|
||||||
[*.yml]
|
[*.{yml,yaml}]
|
||||||
indent_size = 2
|
indent_size = 2
|
||||||
|
|||||||
4
.github/workflows/static.yml
vendored
4
.github/workflows/static.yml
vendored
@ -20,7 +20,7 @@ jobs:
|
|||||||
coverage: none
|
coverage: none
|
||||||
|
|
||||||
- name: Install Dependencies
|
- name: Install Dependencies
|
||||||
run: composer update --no-interaction --prefer-dist --no-progress
|
run: composer update --no-interaction --no-progress
|
||||||
|
|
||||||
- name: Run Rector
|
- name: Run Rector
|
||||||
run: vendor/bin/rector process src --dry-run
|
run: vendor/bin/rector process src --dry-run
|
||||||
@ -48,7 +48,7 @@ jobs:
|
|||||||
coverage: none
|
coverage: none
|
||||||
|
|
||||||
- name: Install Dependencies
|
- name: Install Dependencies
|
||||||
run: composer update --prefer-stable --no-interaction --prefer-dist --no-progress
|
run: composer update --prefer-stable --no-interaction --no-progress
|
||||||
|
|
||||||
- name: Run PHPStan
|
- name: Run PHPStan
|
||||||
run: vendor/bin/phpstan analyse --no-progress
|
run: vendor/bin/phpstan analyse --no-progress
|
||||||
|
|||||||
34
.github/workflows/tests.yml
vendored
34
.github/workflows/tests.yml
vendored
@ -6,43 +6,39 @@ jobs:
|
|||||||
ci:
|
ci:
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: true
|
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||||
php: [7.3, 7.4]
|
php: ['7.3', '7.4', '8.0']
|
||||||
dependency-version: [prefer-lowest, prefer-stable]
|
dependency-version: [prefer-lowest, prefer-stable]
|
||||||
|
|
||||||
name: Tests P${{ matrix.php }} - ${{ matrix.os }} - ${{ matrix.dependency-version }}
|
name: PHP ${{ matrix.php }} - ${{ matrix.os }} - ${{ matrix.dependency-version }}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
|
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
- name: Cache dependencies
|
|
||||||
uses: actions/cache@v1
|
|
||||||
with:
|
|
||||||
path: ~/.composer/cache/files
|
|
||||||
key: dependencies-php-${{ matrix.php }}-composer-${{ hashFiles('composer.json') }}
|
|
||||||
|
|
||||||
- name: Setup PHP
|
- name: Setup PHP
|
||||||
uses: shivammathur/setup-php@v2
|
uses: shivammathur/setup-php@v2
|
||||||
with:
|
with:
|
||||||
php-version: ${{ matrix.php }}
|
php-version: ${{ matrix.php }}
|
||||||
extensions: dom, mbstring, zip
|
tools: composer:v2
|
||||||
coverage: none
|
coverage: none
|
||||||
|
|
||||||
- name: Install Composer dependencies
|
- name: Setup Problem Matches
|
||||||
run: composer update --${{ matrix.dependency-version }} --no-interaction --prefer-dist
|
run: |
|
||||||
|
echo "::add-matcher::${{ runner.tool_cache }}/php.json"
|
||||||
|
echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json"
|
||||||
|
|
||||||
|
- name: Install PHP 7 dependencies
|
||||||
|
run: composer update --${{ matrix.dependency-version }} --no-interaction --no-progress
|
||||||
|
if: "matrix.php < 8"
|
||||||
|
|
||||||
|
- name: Install PHP 8 dependencies
|
||||||
|
run: composer update --${{ matrix.dependency-version }} --ignore-platform-req=php --no-interaction --no-progress
|
||||||
|
if: "matrix.php >= 8"
|
||||||
|
|
||||||
- name: Unit Tests
|
- name: Unit Tests
|
||||||
run: php bin/pest --colors=always --exclude-group=integration
|
run: php bin/pest --colors=always --exclude-group=integration
|
||||||
|
|
||||||
- name: Integration Tests
|
- name: Integration Tests
|
||||||
run: php bin/pest --colors=always --group=integration
|
run: php bin/pest --colors=always --group=integration
|
||||||
|
|
||||||
- name: Setup problem matchers for PHP
|
|
||||||
run: echo "::add-matcher::${{ runner.tool_cache }}/php.json"
|
|
||||||
|
|
||||||
- name: Setup problem matchers for Pest
|
|
||||||
run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json"
|
|
||||||
|
|||||||
@ -17,13 +17,12 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"require": {
|
"require": {
|
||||||
"php": "^7.3",
|
"php": "^7.3 || ^8.0",
|
||||||
"nunomaduro/collision": "^5.0.0-BETA4",
|
"nunomaduro/collision": "^5.0.0-BETA5",
|
||||||
"pestphp/pest-plugin": "^0.3",
|
"pestphp/pest-plugin": "^0.3",
|
||||||
"pestphp/pest-plugin-coverage": "^0.3",
|
"pestphp/pest-plugin-coverage": "^0.3",
|
||||||
"pestphp/pest-plugin-init": "^0.3",
|
"pestphp/pest-plugin-init": "^0.3",
|
||||||
"phpunit/phpunit": "^9.2.6",
|
"phpunit/phpunit": "9.3.7"
|
||||||
"sebastian/environment": "^5.1.2"
|
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
@ -45,7 +44,7 @@
|
|||||||
"require-dev": {
|
"require-dev": {
|
||||||
"illuminate/console": "^7.16.1",
|
"illuminate/console": "^7.16.1",
|
||||||
"illuminate/support": "^7.16.1",
|
"illuminate/support": "^7.16.1",
|
||||||
"mockery/mockery": "^1.4.0",
|
"mockery/mockery": "^1.4.1",
|
||||||
"pestphp/pest-dev-tools": "dev-master"
|
"pestphp/pest-dev-tools": "dev-master"
|
||||||
},
|
},
|
||||||
"minimum-stability": "dev",
|
"minimum-stability": "dev",
|
||||||
|
|||||||
@ -21,6 +21,7 @@ parameters:
|
|||||||
- "# with null as default value#"
|
- "# with null as default value#"
|
||||||
- "#has parameter \\$closure with default value.#"
|
- "#has parameter \\$closure with default value.#"
|
||||||
- "#has parameter \\$description with default value.#"
|
- "#has parameter \\$description with default value.#"
|
||||||
|
- "#Method Pest\\\\Support\\\\Reflection::getParameterClassName\\(\\) has a nullable return type declaration.#"
|
||||||
-
|
-
|
||||||
message: '#Call to an undefined method PHPUnit\\Framework\\Test::getName\(\)#'
|
message: '#Call to an undefined method PHPUnit\\Framework\\Test::getName\(\)#'
|
||||||
path: src/TeamCity.php
|
path: src/TeamCity.php
|
||||||
|
|||||||
31
rector.php
Normal file
31
rector.php
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use Rector\Core\Configuration\Option;
|
||||||
|
use Rector\Set\ValueObject\SetList;
|
||||||
|
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
|
||||||
|
|
||||||
|
return static function (ContainerConfigurator $containerConfigurator): void {
|
||||||
|
$parameters = $containerConfigurator->parameters();
|
||||||
|
|
||||||
|
$parameters->set(Option::AUTO_IMPORT_NAMES, true);
|
||||||
|
|
||||||
|
$parameters->set(Option::SETS, [
|
||||||
|
SetList::ACTION_INJECTION_TO_CONSTRUCTOR_INJECTION,
|
||||||
|
SetList::ARRAY_STR_FUNCTIONS_TO_STATIC_CALL,
|
||||||
|
SetList::CODE_QUALITY,
|
||||||
|
SetList::PHP_53,
|
||||||
|
SetList::PHP_54,
|
||||||
|
SetList::PHP_56,
|
||||||
|
SetList::PHP_70,
|
||||||
|
SetList::PHP_71,
|
||||||
|
SetList::PHP_72,
|
||||||
|
SetList::PHP_73,
|
||||||
|
SetList::PHPSTAN,
|
||||||
|
SetList::PHPUNIT_CODE_QUALITY,
|
||||||
|
SetList::SOLID,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$parameters->set(Option::PATHS, [__DIR__.'/src', __DIR__.'/tests']);
|
||||||
|
};
|
||||||
14
rector.yaml
14
rector.yaml
@ -1,14 +0,0 @@
|
|||||||
# rector.yaml
|
|
||||||
parameters:
|
|
||||||
sets:
|
|
||||||
- 'action-injection-to-constructor-injection'
|
|
||||||
- 'array-str-functions-to-static-call'
|
|
||||||
- 'celebrity'
|
|
||||||
- 'phpstan'
|
|
||||||
- 'phpunit-code-quality'
|
|
||||||
- 'solid'
|
|
||||||
- 'doctrine-code-quality'
|
|
||||||
- 'code-quality'
|
|
||||||
- 'php71'
|
|
||||||
- 'php72'
|
|
||||||
- 'php73'
|
|
||||||
@ -6,8 +6,7 @@ namespace Pest\Actions;
|
|||||||
|
|
||||||
use Pest\Exceptions\AttributeNotSupportedYet;
|
use Pest\Exceptions\AttributeNotSupportedYet;
|
||||||
use Pest\Exceptions\FileOrFolderNotFound;
|
use Pest\Exceptions\FileOrFolderNotFound;
|
||||||
use PHPUnit\TextUI\Configuration\Configuration;
|
use PHPUnit\TextUI\XmlConfiguration\Loader;
|
||||||
use PHPUnit\TextUI\Configuration\Registry;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
@ -30,9 +29,7 @@ final class ValidatesConfiguration
|
|||||||
throw new FileOrFolderNotFound('phpunit.xml');
|
throw new FileOrFolderNotFound('phpunit.xml');
|
||||||
}
|
}
|
||||||
|
|
||||||
$configuration = Registry::getInstance()
|
$configuration = (new Loader())->load($arguments[self::CONFIGURATION_KEY])->phpunit();
|
||||||
->get($arguments[self::CONFIGURATION_KEY])
|
|
||||||
->phpunit();
|
|
||||||
|
|
||||||
if ($configuration->processIsolation()) {
|
if ($configuration->processIsolation()) {
|
||||||
throw new AttributeNotSupportedYet('processIsolation', 'true');
|
throw new AttributeNotSupportedYet('processIsolation', 'true');
|
||||||
|
|||||||
@ -9,6 +9,7 @@ use Pest\Expectation;
|
|||||||
use Pest\Support\ExceptionTrace;
|
use Pest\Support\ExceptionTrace;
|
||||||
use Pest\TestSuite;
|
use Pest\TestSuite;
|
||||||
use PHPUnit\Util\Test;
|
use PHPUnit\Util\Test;
|
||||||
|
use Throwable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* To avoid inheritance conflicts, all the fields related
|
* To avoid inheritance conflicts, all the fields related
|
||||||
@ -148,7 +149,7 @@ trait TestCase
|
|||||||
*
|
*
|
||||||
* @return mixed
|
* @return mixed
|
||||||
*
|
*
|
||||||
* @throws \Throwable
|
* @throws Throwable
|
||||||
*/
|
*/
|
||||||
public function __test()
|
public function __test()
|
||||||
{
|
{
|
||||||
@ -158,7 +159,7 @@ trait TestCase
|
|||||||
/**
|
/**
|
||||||
* @return mixed
|
* @return mixed
|
||||||
*
|
*
|
||||||
* @throws \Throwable
|
* @throws Throwable
|
||||||
*/
|
*/
|
||||||
private function __callClosure(Closure $closure, array $arguments)
|
private function __callClosure(Closure $closure, array $arguments)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -16,9 +16,11 @@ final class Expectation
|
|||||||
/**
|
/**
|
||||||
* The expectation value.
|
* The expectation value.
|
||||||
*
|
*
|
||||||
|
* @readonly
|
||||||
|
*
|
||||||
* @var mixed
|
* @var mixed
|
||||||
*/
|
*/
|
||||||
private $value;
|
public $value;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new expectation.
|
* Creates a new expectation.
|
||||||
@ -412,6 +414,36 @@ final class Expectation
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asserts that the value is a file.
|
||||||
|
*/
|
||||||
|
public function toBeFile(): Expectation
|
||||||
|
{
|
||||||
|
Assert::assertFileExists($this->value);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asserts that the value is a file and is readable.
|
||||||
|
*/
|
||||||
|
public function toBeReadableFile(): Expectation
|
||||||
|
{
|
||||||
|
Assert::assertFileIsReadable($this->value);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asserts that the value is a file and is writable.
|
||||||
|
*/
|
||||||
|
public function toBeWritableFile(): Expectation
|
||||||
|
{
|
||||||
|
Assert::assertFileIsWritable($this->value);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dynamically calls methods on the class without any arguments.
|
* Dynamically calls methods on the class without any arguments.
|
||||||
*
|
*
|
||||||
|
|||||||
@ -157,8 +157,15 @@ final class TestCaseFactory
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Makes a fully qualified class name
|
* Makes a fully qualified class name from the current filename.
|
||||||
* from the given filename.
|
*/
|
||||||
|
public function getClassName(): string
|
||||||
|
{
|
||||||
|
return $this->makeClassFromFilename($this->filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes a fully qualified class name from the given filename.
|
||||||
*/
|
*/
|
||||||
public function makeClassFromFilename(string $filename): string
|
public function makeClassFromFilename(string $filename): string
|
||||||
{
|
{
|
||||||
|
|||||||
@ -6,6 +6,7 @@ namespace Pest\Laravel\Commands;
|
|||||||
|
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
use Illuminate\Support\Facades\File;
|
use Illuminate\Support\Facades\File;
|
||||||
|
use Pest\Console\Thanks;
|
||||||
use Pest\Exceptions\InvalidConsoleArgument;
|
use Pest\Exceptions\InvalidConsoleArgument;
|
||||||
use Pest\Support\Str;
|
use Pest\Support\Str;
|
||||||
|
|
||||||
@ -60,7 +61,9 @@ final class PestInstallCommand extends Command
|
|||||||
$this->output->success('`tests/Pest.php` created successfully.');
|
$this->output->success('`tests/Pest.php` created successfully.');
|
||||||
$this->output->success('`tests/Helpers.php` created successfully.');
|
$this->output->success('`tests/Helpers.php` created successfully.');
|
||||||
|
|
||||||
(new \Pest\Console\Thanks($this->output))();
|
if (!(bool) $this->option('no-interaction')) {
|
||||||
|
(new Thanks($this->output))();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -5,6 +5,7 @@ declare(strict_types=1);
|
|||||||
namespace Pest;
|
namespace Pest;
|
||||||
|
|
||||||
use PHPUnit\Framework\ExpectationFailedException;
|
use PHPUnit\Framework\ExpectationFailedException;
|
||||||
|
use SebastianBergmann\Exporter\Exporter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
@ -40,7 +41,8 @@ final class OppositeExpectation
|
|||||||
return $this->original;
|
return $this->original;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new ExpectationFailedException(sprintf('@todo'));
|
// @phpstan-ignore-next-line
|
||||||
|
$this->throwExpectationFailedExpection($name, $arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -55,6 +57,24 @@ final class OppositeExpectation
|
|||||||
return $this->original;
|
return $this->original;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new ExpectationFailedException(sprintf('@todo'));
|
// @phpstan-ignore-next-line
|
||||||
|
$this->throwExpectationFailedExpection($name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new expectation failed exception
|
||||||
|
* with a nice readable message.
|
||||||
|
*
|
||||||
|
* @param array<int, mixed> $arguments
|
||||||
|
*/
|
||||||
|
private function throwExpectationFailedExpection(string $name, array $arguments = []): void
|
||||||
|
{
|
||||||
|
$exporter = new Exporter();
|
||||||
|
|
||||||
|
$toString = function ($argument) use ($exporter): string {
|
||||||
|
return $exporter->shortenedExport($argument);
|
||||||
|
};
|
||||||
|
|
||||||
|
throw new ExpectationFailedException(sprintf('Expecting %s not %s %s.', $toString($this->original->value), strtolower((string) preg_replace('/(?<!\ )[A-Z]/', ' $0', $name)), implode(' ', array_map(function ($argument) use ($toString): string { return $toString($argument); }, $arguments))));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,6 +9,7 @@ use Pest\Factories\TestCaseFactory;
|
|||||||
use Pest\Support\Backtrace;
|
use Pest\Support\Backtrace;
|
||||||
use Pest\Support\NullClosure;
|
use Pest\Support\NullClosure;
|
||||||
use Pest\TestSuite;
|
use Pest\TestSuite;
|
||||||
|
use PHPUnit\Framework\ExecutionOrderDependency;
|
||||||
use SebastianBergmann\Exporter\Exporter;
|
use SebastianBergmann\Exporter\Exporter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -91,6 +92,12 @@ final class TestCall
|
|||||||
*/
|
*/
|
||||||
public function depends(string ...$tests): TestCall
|
public function depends(string ...$tests): TestCall
|
||||||
{
|
{
|
||||||
|
$className = $this->testCaseFactory->getClassName();
|
||||||
|
|
||||||
|
$tests = array_map(function (string $test) use ($className): ExecutionOrderDependency {
|
||||||
|
return ExecutionOrderDependency::createFromDependsAnnotation($className, $test);
|
||||||
|
}, $tests);
|
||||||
|
|
||||||
$this->testCaseFactory
|
$this->testCaseFactory
|
||||||
->factoryProxies
|
->factoryProxies
|
||||||
->add(Backtrace::file(), Backtrace::line(), 'setDependencies', [$tests]);
|
->add(Backtrace::file(), Backtrace::line(), 'setDependencies', [$tests]);
|
||||||
|
|||||||
@ -11,6 +11,7 @@ use Pest\Exceptions\TestCaseClassOrTraitNotFound;
|
|||||||
use Pest\Factories\TestCaseFactory;
|
use Pest\Factories\TestCaseFactory;
|
||||||
use Pest\Support\Str;
|
use Pest\Support\Str;
|
||||||
use Pest\TestSuite;
|
use Pest\TestSuite;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
@ -52,7 +53,7 @@ final class TestRepository
|
|||||||
if ((!is_dir($path) && $filename === $path) || (is_dir($path) && $startsWith($filename, $path))) {
|
if ((!is_dir($path) && $filename === $path) || (is_dir($path) && $startsWith($filename, $path))) {
|
||||||
foreach ($classOrTraits as $class) {
|
foreach ($classOrTraits as $class) {
|
||||||
if (class_exists($class)) {
|
if (class_exists($class)) {
|
||||||
if ($testCase->class !== \PHPUnit\Framework\TestCase::class) {
|
if ($testCase->class !== TestCase::class) {
|
||||||
throw new TestCaseAlreadyInUse($testCase->class, $class, $filename);
|
throw new TestCaseAlreadyInUse($testCase->class, $class, $filename);
|
||||||
}
|
}
|
||||||
$testCase->class = $class;
|
$testCase->class = $class;
|
||||||
|
|||||||
@ -75,15 +75,16 @@ final class Container
|
|||||||
if ($constructor !== null) {
|
if ($constructor !== null) {
|
||||||
$params = array_map(
|
$params = array_map(
|
||||||
function (ReflectionParameter $param) use ($id) {
|
function (ReflectionParameter $param) use ($id) {
|
||||||
$candidate = null;
|
$candidate = Reflection::getParameterClassName($param);
|
||||||
|
|
||||||
if ($param->getType() !== null && $param->getType()->isBuiltin()) {
|
if ($candidate === null) {
|
||||||
|
$type = $param->getType();
|
||||||
|
if ($type !== null && $type->isBuiltin()) {
|
||||||
$candidate = $param->getName();
|
$candidate = $param->getName();
|
||||||
} elseif ($param->getClass() !== null) {
|
|
||||||
$candidate = $param->getClass()->getName();
|
|
||||||
} else {
|
} else {
|
||||||
throw ShouldNotHappen::fromMessage(sprintf('The type of `$%s` in `%s` cannot be determined.', $id, $param->getName()));
|
throw ShouldNotHappen::fromMessage(sprintf('The type of `$%s` in `%s` cannot be determined.', $id, $param->getName()));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return $this->get($candidate);
|
return $this->get($candidate);
|
||||||
},
|
},
|
||||||
|
|||||||
@ -20,7 +20,7 @@ final class ExceptionTrace
|
|||||||
*
|
*
|
||||||
* @return mixed
|
* @return mixed
|
||||||
*
|
*
|
||||||
* @throws \Throwable
|
* @throws Throwable
|
||||||
*/
|
*/
|
||||||
public static function ensure(Closure $closure)
|
public static function ensure(Closure $closure)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -76,8 +76,8 @@ final class HigherOrderMessage
|
|||||||
Reflection::setPropertyValue($throwable, 'file', $this->filename);
|
Reflection::setPropertyValue($throwable, 'file', $this->filename);
|
||||||
Reflection::setPropertyValue($throwable, 'line', $this->line);
|
Reflection::setPropertyValue($throwable, 'line', $this->line);
|
||||||
|
|
||||||
if ($throwable->getMessage() === sprintf(self::UNDEFINED_METHOD, $this->methodName)) {
|
if ($throwable->getMessage() === self::getUndefinedMethodMessage($target, $this->methodName)) {
|
||||||
/** @var \ReflectionClass $reflection */
|
/** @var ReflectionClass $reflection */
|
||||||
$reflection = new ReflectionClass($target);
|
$reflection = new ReflectionClass($target);
|
||||||
/* @phpstan-ignore-next-line */
|
/* @phpstan-ignore-next-line */
|
||||||
$reflection = $reflection->getParentClass() ?: $reflection;
|
$reflection = $reflection->getParentClass() ?: $reflection;
|
||||||
@ -87,4 +87,13 @@ final class HigherOrderMessage
|
|||||||
throw $throwable;
|
throw $throwable;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static function getUndefinedMethodMessage(object $target, string $methodName): string
|
||||||
|
{
|
||||||
|
if (\PHP_MAJOR_VERSION >= 8) {
|
||||||
|
return sprintf(sprintf(self::UNDEFINED_METHOD, sprintf('%s::%s()', get_class($target), $methodName)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return sprintf(self::UNDEFINED_METHOD, $methodName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,6 +5,7 @@ declare(strict_types=1);
|
|||||||
namespace Pest\Support;
|
namespace Pest\Support;
|
||||||
|
|
||||||
use ReflectionClass;
|
use ReflectionClass;
|
||||||
|
use Throwable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
@ -51,12 +52,12 @@ final class HigherOrderTapProxy
|
|||||||
try {
|
try {
|
||||||
// @phpstan-ignore-next-line
|
// @phpstan-ignore-next-line
|
||||||
return $this->target->{$property};
|
return $this->target->{$property};
|
||||||
} catch (\Throwable $throwable) {
|
} catch (Throwable $throwable) {
|
||||||
Reflection::setPropertyValue($throwable, 'file', Backtrace::file());
|
Reflection::setPropertyValue($throwable, 'file', Backtrace::file());
|
||||||
Reflection::setPropertyValue($throwable, 'line', Backtrace::line());
|
Reflection::setPropertyValue($throwable, 'line', Backtrace::line());
|
||||||
|
|
||||||
if (Str::startsWith($message = $throwable->getMessage(), self::UNDEFINED_PROPERTY)) {
|
if (Str::startsWith($message = $throwable->getMessage(), self::UNDEFINED_PROPERTY)) {
|
||||||
/** @var \ReflectionClass $reflection */
|
/** @var ReflectionClass $reflection */
|
||||||
$reflection = (new ReflectionClass($this->target))->getParentClass();
|
$reflection = (new ReflectionClass($this->target))->getParentClass();
|
||||||
Reflection::setPropertyValue($throwable, 'message', sprintf('Undefined property %s::$%s', $reflection->getName(), $property));
|
Reflection::setPropertyValue($throwable, 'message', sprintf('Undefined property %s::$%s', $reflection->getName(), $property));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,6 +9,8 @@ use Pest\Exceptions\ShouldNotHappen;
|
|||||||
use ReflectionClass;
|
use ReflectionClass;
|
||||||
use ReflectionException;
|
use ReflectionException;
|
||||||
use ReflectionFunction;
|
use ReflectionFunction;
|
||||||
|
use ReflectionNamedType;
|
||||||
|
use ReflectionParameter;
|
||||||
use ReflectionProperty;
|
use ReflectionProperty;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -117,4 +119,32 @@ final class Reflection
|
|||||||
$reflectionProperty->setAccessible(true);
|
$reflectionProperty->setAccessible(true);
|
||||||
$reflectionProperty->setValue($object, $value);
|
$reflectionProperty->setValue($object, $value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the class name of the given parameter's type, if possible.
|
||||||
|
*
|
||||||
|
* @see https://github.com/laravel/framework/blob/v6.18.25/src/Illuminate/Support/Reflector.php
|
||||||
|
*/
|
||||||
|
public static function getParameterClassName(ReflectionParameter $parameter): ?string
|
||||||
|
{
|
||||||
|
$type = $parameter->getType();
|
||||||
|
|
||||||
|
if (!$type instanceof ReflectionNamedType || $type->isBuiltin()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$name = $type->getName();
|
||||||
|
|
||||||
|
if (($class = $parameter->getDeclaringClass()) instanceof ReflectionClass) {
|
||||||
|
if ($name === 'self') {
|
||||||
|
return $class->getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($name === 'parent' && ($parent = $class->getParentClass()) instanceof ReflectionClass) {
|
||||||
|
return $parent->getName();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $name;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,6 +10,7 @@ use Pest\Repositories\AfterEachRepository;
|
|||||||
use Pest\Repositories\BeforeAllRepository;
|
use Pest\Repositories\BeforeAllRepository;
|
||||||
use Pest\Repositories\BeforeEachRepository;
|
use Pest\Repositories\BeforeEachRepository;
|
||||||
use Pest\Repositories\TestRepository;
|
use Pest\Repositories\TestRepository;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
@ -19,7 +20,7 @@ final class TestSuite
|
|||||||
/**
|
/**
|
||||||
* Holds the current test case.
|
* Holds the current test case.
|
||||||
*
|
*
|
||||||
* @var \PHPUnit\Framework\TestCase|null
|
* @var TestCase|null
|
||||||
*/
|
*/
|
||||||
public $test;
|
public $test;
|
||||||
|
|
||||||
|
|||||||
@ -44,8 +44,8 @@ function dataset(string $name, $dataset): void
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The uses function adds the binds the
|
* The uses function binds the given
|
||||||
* given arguments to test closures.
|
* arguments to test closures.
|
||||||
*/
|
*/
|
||||||
function uses(string ...$classAndTraits): UsesCall
|
function uses(string ...$classAndTraits): UsesCall
|
||||||
{
|
{
|
||||||
|
|||||||
@ -39,6 +39,11 @@
|
|||||||
PASS Tests\Expect\toBeFalse
|
PASS Tests\Expect\toBeFalse
|
||||||
✓ strict comparisons
|
✓ strict comparisons
|
||||||
✓ failures
|
✓ failures
|
||||||
|
✓ not failures
|
||||||
|
|
||||||
|
PASS Tests\Expect\toBeFile
|
||||||
|
✓ pass
|
||||||
|
✓ failures
|
||||||
✓ not failures
|
✓ not failures
|
||||||
|
|
||||||
PASS Tests\Expect\toBeFloat
|
PASS Tests\Expect\toBeFloat
|
||||||
@ -109,6 +114,11 @@
|
|||||||
PASS Tests\Expect\toBeReadableDirectory
|
PASS Tests\Expect\toBeReadableDirectory
|
||||||
✓ pass
|
✓ pass
|
||||||
✓ failures
|
✓ failures
|
||||||
|
✓ not failures
|
||||||
|
|
||||||
|
PASS Tests\Expect\toBeReadableFile
|
||||||
|
✓ pass
|
||||||
|
✓ failures
|
||||||
✓ not failures
|
✓ not failures
|
||||||
|
|
||||||
PASS Tests\Expect\toBeResource
|
PASS Tests\Expect\toBeResource
|
||||||
@ -134,6 +144,11 @@
|
|||||||
PASS Tests\Expect\toBeWritableDirectory
|
PASS Tests\Expect\toBeWritableDirectory
|
||||||
✓ pass
|
✓ pass
|
||||||
✓ failures
|
✓ failures
|
||||||
|
✓ not failures
|
||||||
|
|
||||||
|
PASS Tests\Expect\toBeWritableFile
|
||||||
|
✓ pass
|
||||||
|
✓ failures
|
||||||
✓ not failures
|
✓ not failures
|
||||||
|
|
||||||
PASS Tests\Expect\toContain
|
PASS Tests\Expect\toContain
|
||||||
@ -219,14 +234,6 @@
|
|||||||
✓ it creates unique test case names with ('Name 1', Pest\Plugin Object (), true) #3
|
✓ it creates unique test case names with ('Name 1', Pest\Plugin Object (), true) #3
|
||||||
✓ it creates unique test case names - count
|
✓ it creates unique test case names - count
|
||||||
|
|
||||||
PASS Tests\Features\Depends
|
|
||||||
✓ first
|
|
||||||
✓ second
|
|
||||||
✓ depends
|
|
||||||
✓ depends with ...params
|
|
||||||
✓ depends with defined arguments
|
|
||||||
✓ depends run test only once
|
|
||||||
|
|
||||||
PASS Tests\Features\Exceptions
|
PASS Tests\Features\Exceptions
|
||||||
✓ it gives access the the underlying expectException
|
✓ it gives access the the underlying expectException
|
||||||
✓ it catch exceptions
|
✓ it catch exceptions
|
||||||
@ -337,5 +344,12 @@
|
|||||||
WARN Tests\Visual\Success
|
WARN Tests\Visual\Success
|
||||||
- visual snapshot of test suite on success
|
- visual snapshot of test suite on success
|
||||||
|
|
||||||
Tests: 6 skipped, 198 passed
|
PASS Tests\Features\Depends
|
||||||
Time: 5.46s
|
✓ first
|
||||||
|
✓ second
|
||||||
|
✓ depends
|
||||||
|
✓ depends with ...params
|
||||||
|
✓ depends with defined arguments
|
||||||
|
✓ depends run test only once
|
||||||
|
|
||||||
|
Tests: 6 skipped, 207 passed
|
||||||
|
|||||||
23
tests/Expect/toBeFile.php
Normal file
23
tests/Expect/toBeFile.php
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use PHPUnit\Framework\ExpectationFailedException;
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
touch($this->tempFile = sys_get_temp_dir() . '/fake.file');
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(function () {
|
||||||
|
unlink($this->tempFile);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('pass', function () {
|
||||||
|
expect($this->tempFile)->toBeFile();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('failures', function () {
|
||||||
|
expect('/random/path/whatever.file')->toBeFile();
|
||||||
|
})->throws(ExpectationFailedException::class);
|
||||||
|
|
||||||
|
test('not failures', function () {
|
||||||
|
expect($this->tempFile)->not->toBeFile();
|
||||||
|
})->throws(ExpectationFailedException::class);
|
||||||
@ -3,13 +3,13 @@
|
|||||||
use PHPUnit\Framework\ExpectationFailedException;
|
use PHPUnit\Framework\ExpectationFailedException;
|
||||||
|
|
||||||
test('pass', function () {
|
test('pass', function () {
|
||||||
expect(sys_get_temp_dir())->toBeWritableDirectory();
|
expect(sys_get_temp_dir())->toBeReadableDirectory();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('failures', function () {
|
test('failures', function () {
|
||||||
expect('/random/path/whatever')->toBeWritableDirectory();
|
expect('/random/path/whatever')->toBeReadableDirectory();
|
||||||
})->throws(ExpectationFailedException::class);
|
})->throws(ExpectationFailedException::class);
|
||||||
|
|
||||||
test('not failures', function () {
|
test('not failures', function () {
|
||||||
expect(sys_get_temp_dir())->not->toBeWritableDirectory();
|
expect(sys_get_temp_dir())->not->toBeReadableDirectory();
|
||||||
})->throws(ExpectationFailedException::class);
|
})->throws(ExpectationFailedException::class);
|
||||||
|
|||||||
23
tests/Expect/toBeReadableFile.php
Normal file
23
tests/Expect/toBeReadableFile.php
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use PHPUnit\Framework\ExpectationFailedException;
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
touch($this->tempFile = sys_get_temp_dir() . '/fake.file');
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(function () {
|
||||||
|
unlink($this->tempFile);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('pass', function () {
|
||||||
|
expect($this->tempFile)->toBeReadableFile();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('failures', function () {
|
||||||
|
expect('/random/path/whatever.file')->toBeReadableFile();
|
||||||
|
})->throws(ExpectationFailedException::class);
|
||||||
|
|
||||||
|
test('not failures', function () {
|
||||||
|
expect($this->tempFile)->not->toBeReadableFile();
|
||||||
|
})->throws(ExpectationFailedException::class);
|
||||||
23
tests/Expect/toBeWritableFile.php
Normal file
23
tests/Expect/toBeWritableFile.php
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use PHPUnit\Framework\ExpectationFailedException;
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
touch($this->tempFile = sys_get_temp_dir() . '/fake.file');
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(function () {
|
||||||
|
unlink($this->tempFile);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('pass', function () {
|
||||||
|
expect($this->tempFile)->toBeWritableFile();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('failures', function () {
|
||||||
|
expect('/random/path/whatever.file')->toBeWritableFile();
|
||||||
|
})->throws(ExpectationFailedException::class);
|
||||||
|
|
||||||
|
test('not failures', function () {
|
||||||
|
expect($this->tempFile)->not->toBeWritableFile();
|
||||||
|
})->throws(ExpectationFailedException::class);
|
||||||
@ -23,7 +23,7 @@ test('visual snapshot of test suite on success', function () {
|
|||||||
array_pop($output);
|
array_pop($output);
|
||||||
array_pop($output);
|
array_pop($output);
|
||||||
|
|
||||||
expect(file_get_contents($snapshot))->toContain(implode("\n", $output));
|
expect(implode("\n", $output))->toContain(file_get_contents($snapshot));
|
||||||
}
|
}
|
||||||
})->skip(!getenv('REBUILD_SNAPSHOTS') && getenv('EXCLUDE'))
|
})->skip(!getenv('REBUILD_SNAPSHOTS') && getenv('EXCLUDE'))
|
||||||
->skip(PHP_OS_FAMILY === 'Windows');
|
->skip(PHP_OS_FAMILY === 'Windows');
|
||||||
|
|||||||
Reference in New Issue
Block a user