Merge branch 'master' of https://github.com/pestphp/pest into feat-teamcity

 Conflicts:
	phpstan.neon
This commit is contained in:
Oliver Nybroe
2020-08-15 08:30:46 +02:00
28 changed files with 290 additions and 84 deletions

View File

@ -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

View File

@ -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

View File

@ -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"

View File

@ -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",

View File

@ -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
View 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']);
};

View File

@ -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'

View File

@ -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');

View File

@ -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)
{ {

View File

@ -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.
* *

View File

@ -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
{ {

View File

@ -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))();
}
} }
/** /**

View File

@ -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))));
} }
} }

View File

@ -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]);

View File

@ -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;

View File

@ -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);
}, },

View File

@ -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)
{ {

View File

@ -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);
}
} }

View File

@ -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));
} }

View File

@ -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;
}
} }

View File

@ -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;

View File

@ -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
{ {

View File

@ -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
View 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);

View File

@ -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);

View 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);

View 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);

View File

@ -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');