diff --git a/.github/workflows/static.yml b/.github/workflows/static.yml index 09e0d064..fc8eb823 100644 --- a/.github/workflows/static.yml +++ b/.github/workflows/static.yml @@ -20,10 +20,10 @@ jobs: coverage: none - name: Install Dependencies - run: composer update --no-interaction --no-progress + run: composer update --no-interaction --no-progress --ansi - name: Run PHP-CS-Fixer - run: PHP_CS_FIXER_IGNORE_ENV=true vendor/bin/php-cs-fixer fix -v --allow-risky=yes --dry-run + run: PHP_CS_FIXER_IGNORE_ENV=true vendor/bin/php-cs-fixer fix -v --allow-risky=yes --dry-run --ansi phpstan: runs-on: ubuntu-latest @@ -45,7 +45,7 @@ jobs: coverage: none - name: Install Dependencies - run: composer update --prefer-stable --no-interaction --no-progress + run: composer update --prefer-stable --no-interaction --no-progress --ansi - name: Run PHPStan - run: vendor/bin/phpstan analyse --no-progress --debug + run: vendor/bin/phpstan analyse --no-progress --debug --ansi diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 9245e846..38eb41d1 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -36,7 +36,7 @@ jobs: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json" - name: Install PHP dependencies - run: composer update --${{ matrix.dependency-version }} --no-interaction --no-progress + run: composer update --${{ matrix.dependency-version }} --no-interaction --no-progress --ansi - name: Unit Tests run: php bin/pest --colors=always --exclude-group=integration diff --git a/README.md b/README.md index 3f710c49..a5f32bcf 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,7 @@ + + +------ +

PEST

@@ -21,6 +25,7 @@ We would like to extend our thanks to the following sponsors for funding Pest de ### Platinum Sponsors +- **[Advent](https://advent.dev)** - **[Spatie](https://spatie.be)** - **[Worksome](https://www.worksome.com/)** diff --git a/src/Bootstrappers/BootFiles.php b/src/Bootstrappers/BootFiles.php index 51781ff2..5817c3a8 100644 --- a/src/Bootstrappers/BootFiles.php +++ b/src/Bootstrappers/BootFiles.php @@ -48,6 +48,7 @@ final class BootFiles if (is_dir($filename)) { $directory = new RecursiveDirectoryIterator($filename); $iterator = new RecursiveIteratorIterator($directory); + /** @var \DirectoryIterator $file */ foreach ($iterator as $file) { $this->load($file->__toString()); } diff --git a/src/Concerns/Pipeable.php b/src/Concerns/Pipeable.php index 79f32055..d1df162e 100644 --- a/src/Concerns/Pipeable.php +++ b/src/Concerns/Pipeable.php @@ -43,7 +43,7 @@ trait Pipeable $this->pipe($name, function ($next, ...$arguments) use ($handler, $filter) { /* @phpstan-ignore-next-line */ if ($filter($this->value, ...$arguments)) { - //@phpstan-ignore-next-line + // @phpstan-ignore-next-line $handler->bindTo($this, get_class($this))(...$arguments); return; diff --git a/src/Expectation.php b/src/Expectation.php index 191d762e..fd771e41 100644 --- a/src/Expectation.php +++ b/src/Expectation.php @@ -76,6 +76,22 @@ final class Expectation return $this->toBeJson()->and($value); } + /** + * Dump the expectation value. + * + * @return self + */ + public function dump(mixed ...$arguments): self + { + if (function_exists('dump')) { + dump($this->value, ...$arguments); + } else { + var_dump($this->value); + } + + return $this; + } + /** * Dump the expectation value and end the script. * @@ -151,7 +167,6 @@ final class Expectation throw new BadMethodCallException('Expectation value is not iterable.'); } - //@phpstan-ignore-next-line $value = is_array($this->value) ? $this->value : iterator_to_array($this->value); $keys = array_keys($value); $values = array_values($value); @@ -292,7 +307,7 @@ final class Expectation private function getExpectationClosure(string $name): Closure { if (method_exists(Mixins\Expectation::class, $name)) { - //@phpstan-ignore-next-line + // @phpstan-ignore-next-line return Closure::fromCallable([new Mixins\Expectation($this->value), $name]); } diff --git a/src/Factories/Annotations/CoversNothing.php b/src/Factories/Annotations/CoversNothing.php new file mode 100644 index 00000000..8faaca1f --- /dev/null +++ b/src/Factories/Annotations/CoversNothing.php @@ -0,0 +1,30 @@ + $annotations + * + * @return array + */ + public function __invoke(TestCaseMethodFactory $method, array $annotations): array + { + if (($method->covers[0] ?? null) instanceof CoversNothingFactory) { + $annotations[] = '@coversNothing'; + } + + return $annotations; + } +} diff --git a/src/Factories/Attributes/Attribute.php b/src/Factories/Attributes/Attribute.php new file mode 100644 index 00000000..e53fbe13 --- /dev/null +++ b/src/Factories/Attributes/Attribute.php @@ -0,0 +1,30 @@ + $attributes + * + * @return array + */ + public function __invoke(TestCaseMethodFactory $method, array $attributes): array // @phpstan-ignore-line + { + return $attributes; + } +} diff --git a/src/Factories/Attributes/Covers.php b/src/Factories/Attributes/Covers.php new file mode 100644 index 00000000..d6d41c4a --- /dev/null +++ b/src/Factories/Attributes/Covers.php @@ -0,0 +1,47 @@ + $attributes + * + * @return array + */ + public function __invoke(TestCaseMethodFactory $method, array $attributes): array + { + foreach ($method->covers as $covering) { + if ($covering instanceof CoversClass) { + // Prepend a backslash for FQN classes + if (str_contains($covering->class, '\\')) { + $covering->class = '\\' . $covering->class; + } + + $attributes[] = "#[\PHPUnit\Framework\Attributes\CoversClass({$covering->class}::class)]"; + } elseif ($covering instanceof CoversFunction) { + $attributes[] = "#[\PHPUnit\Framework\Attributes\CoversFunction('{$covering->function}')]"; + } + } + + return $attributes; + } +} diff --git a/src/Factories/Covers/CoversClass.php b/src/Factories/Covers/CoversClass.php new file mode 100644 index 00000000..44f58487 --- /dev/null +++ b/src/Factories/Covers/CoversClass.php @@ -0,0 +1,15 @@ +> + */ + private static array $attributes = [ + Attributes\Covers::class, ]; /** @@ -141,11 +151,33 @@ final class TestCaseFactory $classFQN .= $className; } + $classAvailableAttributes = array_filter(self::$attributes, fn (string $attribute) => $attribute::ABOVE_CLASS); + $methodAvailableAttributes = array_filter(self::$attributes, fn (string $attribute) => !$attribute::ABOVE_CLASS); + + $classAttributes = []; + + foreach ($classAvailableAttributes as $attribute) { + $classAttributes = array_reduce( + $methods, + fn (array $carry, TestCaseMethodFactory $methodFactory) => (new $attribute())->__invoke($methodFactory, $carry), + $classAttributes + ); + } + $methodsCode = implode('', array_map( - fn (TestCaseMethodFactory $methodFactory) => $methodFactory->buildForEvaluation($classFQN, self::$annotations), + fn (TestCaseMethodFactory $methodFactory) => $methodFactory->buildForEvaluation( + $classFQN, + self::$annotations, + $methodAvailableAttributes + ), $methods )); + $classAttributesCode = implode('', array_map( + static fn (string $attribute) => sprintf("\n %s", $attribute), + array_unique($classAttributes), + )); + try { eval(" namespace $namespace; @@ -153,6 +185,7 @@ final class TestCaseFactory use Pest\Repositories\DatasetsRepository as __PestDatasets; use Pest\TestSuite as __PestTestSuite; + $classAttributesCode final class $className extends $baseClass implements $hasPrintableTestCaseClassFQN { $traitsCode diff --git a/src/Factories/TestCaseMethodFactory.php b/src/Factories/TestCaseMethodFactory.php index 987a2d27..effd525a 100644 --- a/src/Factories/TestCaseMethodFactory.php +++ b/src/Factories/TestCaseMethodFactory.php @@ -47,6 +47,13 @@ final class TestCaseMethodFactory */ public array $groups = []; + /** + * The covered classes and functions, if any. + * + * @var array + */ + public array $covers = []; + /** * Creates a new Factory instance. */ @@ -106,9 +113,10 @@ final class TestCaseMethodFactory /** * Creates a PHPUnit method as a string ready for evaluation. * - * @param array $annotationsToUse + * @param array $annotationsToUse + * @param array> $attributesToUse */ - public function buildForEvaluation(string $classFQN, array $annotationsToUse): string + public function buildForEvaluation(string $classFQN, array $annotationsToUse, array $attributesToUse): string { if ($this->description === null) { throw ShouldNotHappen::fromMessage('The test description may not be empty.'); @@ -122,12 +130,17 @@ final class TestCaseMethodFactory $datasetsCode = ''; $annotations = ['@test']; + $attributes = []; foreach ($annotationsToUse as $annotation) { /** @phpstan-ignore-next-line */ $annotations = (new $annotation())->__invoke($this, $annotations); } + foreach ($attributesToUse as $attribute) { + $attributes = (new $attribute())->__invoke($this, $attributes); + } + if (count($this->datasets) > 0) { $dataProviderName = $methodName . '_dataset'; $annotations[] = "@dataProvider $dataProviderName"; @@ -138,10 +151,15 @@ final class TestCaseMethodFactory static fn ($annotation) => sprintf("\n * %s", $annotation), $annotations, )); + $attributes = implode('', array_map( + static fn ($attribute) => sprintf("\n %s", $attribute), $attributes, + )); + return <<__runTest( diff --git a/src/Kernel.php b/src/Kernel.php index 67c4dcf9..98bf867c 100644 --- a/src/Kernel.php +++ b/src/Kernel.php @@ -37,7 +37,7 @@ final class Kernel public static function boot(): self { foreach (self::$bootstrappers as $bootstrapper) { - //@phpstan-ignore-next-line + // @phpstan-ignore-next-line (new $bootstrapper())->__invoke(); } diff --git a/src/Mixins/Expectation.php b/src/Mixins/Expectation.php index 3fbd2110..337cc9cc 100644 --- a/src/Mixins/Expectation.php +++ b/src/Mixins/Expectation.php @@ -6,6 +6,7 @@ namespace Pest\Mixins; use BadMethodCallException; use Closure; +use Error; use InvalidArgumentException; use Pest\Exceptions\InvalidExpectationValue; use Pest\Support\Arr; @@ -282,7 +283,7 @@ final class Expectation { $this->toBeObject(); - //@phpstan-ignore-next-line + // @phpstan-ignore-next-line Assert::assertTrue(property_exists($this->value, $name)); if (func_num_args() > 1) { @@ -533,7 +534,7 @@ final class Expectation { Assert::assertIsString($this->value); - //@phpstan-ignore-next-line + // @phpstan-ignore-next-line Assert::assertJson($this->value); return $this; @@ -579,7 +580,7 @@ final class Expectation try { Assert::assertTrue(Arr::has($array, $key)); - /* @phpstan-ignore-next-line */ + /* @phpstan-ignore-next-line */ } catch (ExpectationFailedException $exception) { throw new ExpectationFailedException("Failed asserting that an array has the key '$key'", $exception->getComparisonFailure()); } @@ -822,8 +823,12 @@ final class Expectation try { ($this->value)(); - } catch (Throwable $e) { // @phpstan-ignore-line + } catch (Throwable $e) { if (!class_exists($exception)) { + if ($e instanceof Error && $e->getMessage() === "Class \"$exception\" not found") { + throw $e; + } + Assert::assertStringContainsString($exception, $e->getMessage()); return $this; diff --git a/src/PendingCalls/TestCall.php b/src/PendingCalls/TestCall.php index 56172023..0afdf9d6 100644 --- a/src/PendingCalls/TestCall.php +++ b/src/PendingCalls/TestCall.php @@ -5,6 +5,10 @@ declare(strict_types=1); namespace Pest\PendingCalls; use Closure; +use InvalidArgumentException; +use Pest\Factories\Covers\CoversClass; +use Pest\Factories\Covers\CoversFunction; +use Pest\Factories\Covers\CoversNothing; use Pest\Factories\TestCaseMethodFactory; use Pest\Support\Backtrace; use Pest\Support\HigherOrderCallables; @@ -45,9 +49,11 @@ final class TestCall /** * Asserts that the test throws the given `$exceptionClass` when called. */ - public function throws(string $exception, string $exceptionMessage = null): TestCall + public function throws(string|int $exception, string $exceptionMessage = null, int $exceptionCode = null): TestCall { - if (class_exists($exception)) { + if (is_int($exception)) { + $exceptionCode = $exception; + } elseif (class_exists($exception)) { $this->testCaseMethod ->proxies ->add(Backtrace::file(), Backtrace::line(), 'expectException', [$exception]); @@ -61,6 +67,12 @@ final class TestCall ->add(Backtrace::file(), Backtrace::line(), 'expectExceptionMessage', [$exceptionMessage]); } + if (is_int($exceptionCode)) { + $this->testCaseMethod + ->proxies + ->add(Backtrace::file(), Backtrace::line(), 'expectExceptionCode', [$exceptionCode]); + } + return $this; } @@ -69,7 +81,7 @@ final class TestCall * * @param (callable(): bool)|bool $condition */ - public function throwsIf(callable|bool $condition, string $exception, string $exceptionMessage = null): TestCall + public function throwsIf(callable|bool $condition, string|int $exception, string $exceptionMessage = null, int $exceptionCode = null): TestCall { $condition = is_callable($condition) ? $condition @@ -78,7 +90,7 @@ final class TestCall }; if ($condition()) { - return $this->throws($exception, $exceptionMessage); + return $this->throws($exception, $exceptionMessage, $exceptionCode); } return $this; @@ -160,6 +172,63 @@ final class TestCall return $this; } + /** + * Sets the covered classes or methods. + */ + public function covers(string ...$classesOrFunctions): TestCall + { + foreach ($classesOrFunctions as $classOrFunction) { + $isClass = class_exists($classOrFunction); + $isMethod = function_exists($classOrFunction); + + if (!$isClass && !$isMethod) { + throw new InvalidArgumentException(sprintf('No class or method named "%s" has been found.', $classOrFunction)); + } + + if ($isClass) { + $this->coversClass($classOrFunction); + } else { + $this->coversFunction($classOrFunction); + } + } + + return $this; + } + + /** + * Sets the covered classes. + */ + public function coversClass(string ...$classes): TestCall + { + foreach ($classes as $class) { + $this->testCaseMethod->covers[] = new CoversClass($class); + } + + return $this; + } + + /** + * Sets the covered functions. + */ + public function coversFunction(string ...$functions): TestCall + { + foreach ($functions as $function) { + $this->testCaseMethod->covers[] = new CoversFunction($function); + } + + return $this; + } + + /** + * Sets that the current test covers nothing. + */ + public function coversNothing(): TestCall + { + $this->testCaseMethod->covers = [new CoversNothing()]; + + return $this; + } + /** * Informs the test runner that no expectations happen in this test, * and its purpose is simply to check whether the given code can diff --git a/src/Repositories/DatasetsRepository.php b/src/Repositories/DatasetsRepository.php index d8a57bfa..385d4d47 100644 --- a/src/Repositories/DatasetsRepository.php +++ b/src/Repositories/DatasetsRepository.php @@ -156,11 +156,11 @@ final class DatasetsRepository $datasets[$index] = iterator_to_array($datasets[$index]); } - //@phpstan-ignore-next-line + // @phpstan-ignore-next-line foreach ($datasets[$index] as $key => $values) { $values = is_array($values) ? $values : [$values]; $processedDataset[] = [ - 'label' => self::getDatasetDescription($key, $values), //@phpstan-ignore-line + 'label' => self::getDatasetDescription($key, $values), // @phpstan-ignore-line 'values' => $values, ]; } @@ -189,7 +189,7 @@ final class DatasetsRepository $result = $tmp; } - //@phpstan-ignore-next-line + // @phpstan-ignore-next-line return $result; } diff --git a/src/Support/Container.php b/src/Support/Container.php index 1f6b45cd..67cd4e39 100644 --- a/src/Support/Container.php +++ b/src/Support/Container.php @@ -85,7 +85,7 @@ final class Container } } - //@phpstan-ignore-next-line + // @phpstan-ignore-next-line return $this->get($candidate); }, $constructor->getParameters() diff --git a/src/Support/HigherOrderMessageCollection.php b/src/Support/HigherOrderMessageCollection.php index 54bef82a..6d4bca2b 100644 --- a/src/Support/HigherOrderMessageCollection.php +++ b/src/Support/HigherOrderMessageCollection.php @@ -40,7 +40,7 @@ final class HigherOrderMessageCollection public function chain(object $target): void { foreach ($this->messages as $message) { - //@phpstan-ignore-next-line + // @phpstan-ignore-next-line $target = $message->call($target) ?? $target; } } diff --git a/tests/Features/Coverage.php b/tests/Features/Coverage.php index e43ae180..7af61548 100644 --- a/tests/Features/Coverage.php +++ b/tests/Features/Coverage.php @@ -8,7 +8,7 @@ use Symfony\Component\Console\Output\ConsoleOutput; it('has plugin')->assertTrue(class_exists(CoveragePlugin::class)); it('adds coverage if --coverage exist', function () { - $plugin = new CoveragePlugin(new ConsoleOutput()); + $plugin = new CoveragePlugin(new ConsoleOutput()); $testSuite = TestSuite::getInstance(); expect($plugin->coverage)->toBeFalse(); diff --git a/tests/Features/Covers.php b/tests/Features/Covers.php new file mode 100644 index 00000000..63c3d8a1 --- /dev/null +++ b/tests/Features/Covers.php @@ -0,0 +1,78 @@ +getAttributes(); + + expect($attributes[0]->getName())->toBe('PHPUnit\Framework\Attributes\CoversClass'); + expect($attributes[0]->getArguments()[0])->toBe('P\Tests\Features\TestCoversClass1'); +})->coversClass(TestCoversClass1::class); + +it('uses the correct PHPUnit attribute for function', function () { + $attributes = (new ReflectionClass($this))->getAttributes(); + + expect($attributes[1]->getName())->toBe('PHPUnit\Framework\Attributes\CoversFunction'); + expect($attributes[1]->getArguments()[0])->toBe('foo'); +})->coversFunction('foo'); + +it('removes duplicated attributes', function () { + $attributes = (new ReflectionClass($this))->getAttributes(); + + expect($attributes[2]->getName())->toBe('PHPUnit\Framework\Attributes\CoversClass'); + expect($attributes[2]->getArguments()[0])->toBe('P\Tests\Features\TestCoversClass2'); + expect($attributes[3]->getName())->toBe('PHPUnit\Framework\Attributes\CoversClass'); + expect($attributes[3]->getArguments()[0])->toBe('Pest\Factories\Attributes\Covers'); + expect($attributes[4]->getName())->toBe('PHPUnit\Framework\Attributes\CoversFunction'); + expect($attributes[4]->getArguments()[0])->toBe('bar'); + expect($attributes[5]->getName())->toBe('PHPUnit\Framework\Attributes\CoversFunction'); + expect($attributes[5]->getArguments()[0])->toBe('baz'); +}) + ->coversClass(TestCoversClass2::class, TestCoversClass1::class, Covers::class) + ->coversFunction('bar', 'foo', 'baz'); + +it('guesses if the given argument is a class or function', function () { + $attributes = (new ReflectionClass($this))->getAttributes(); + + expect($attributes[6]->getName())->toBe('PHPUnit\Framework\Attributes\CoversClass'); + expect($attributes[6]->getArguments()[0])->toBe('P\Tests\Features\TestCoversClass3'); + expect($attributes[7]->getName())->toBe('PHPUnit\Framework\Attributes\CoversFunction'); + expect($attributes[7]->getArguments()[0])->toBe('testCoversFunction'); +})->covers(TestCoversClass3::class, 'testCoversFunction'); + +it('appends CoversNothing to method attributes', function () { + $phpDoc = (new ReflectionClass($this))->getMethod($this->getName()); + + expect(str_contains($phpDoc->getDocComment(), '* @coversNothing'))->toBeTrue(); +})->coversNothing(); + +it('does not append CoversNothing to other methods', function () { + $phpDoc = (new ReflectionClass($this))->getMethod($this->getName()); + + expect(str_contains($phpDoc->getDocComment(), '* @coversNothing'))->toBeFalse(); +}); + +it('throws exception if no class nor method has been found', function () { + $testCall = new TestCall(TestSuite::getInstance(), 'filename', 'description', fn () => 'closure'); + + $testCall->covers('fakeName'); +})->throws(InvalidArgumentException::class, 'No class or method named "fakeName" has been found.'); diff --git a/tests/Features/Exceptions.php b/tests/Features/Exceptions.php index 9970c2a9..71482fbe 100644 --- a/tests/Features/Exceptions.php +++ b/tests/Features/Exceptions.php @@ -14,10 +14,18 @@ it('catch exceptions and messages', function () { throw new Exception('Something bad happened'); })->throws(Exception::class, 'Something bad happened'); +it('catch exceptions, messages and code', function () { + throw new Exception('Something bad happened', 1); +})->throws(Exception::class, 'Something bad happened', 1); + it('can just define the message', function () { throw new Exception('Something bad happened'); })->throws('Something bad happened'); +it('can just define the code', function () { + throw new Exception('Something bad happened', 1); +})->throws(1); + it('not catch exceptions if given condition is false', function () { $this->assertTrue(true); })->throwsIf(false, Exception::class); @@ -30,10 +38,22 @@ it('catch exceptions and messages if given condition is true', function () { throw new Exception('Something bad happened'); })->throwsIf(true, Exception::class, 'Something bad happened'); +it('catch exceptions, messages and code if given condition is true', function () { + throw new Exception('Something bad happened', 1); +})->throwsIf(true, Exception::class, 'Something bad happened', 1); + it('can just define the message if given condition is true', function () { throw new Exception('Something bad happened'); })->throwsIf(true, 'Something bad happened'); +it('can just define the code if given condition is true', function () { + throw new Exception('Something bad happened', 1); +})->throwsIf(true, 1); + it('can just define the message if given condition is 1', function () { throw new Exception('Something bad happened'); })->throwsIf(1, 'Something bad happened'); + +it('can just define the code if given condition is 1', function () { + throw new Exception('Something bad happened', 1); +})->throwsIf(1, 1); diff --git a/tests/Features/Expect/pipes.php b/tests/Features/Expect/pipes.php index 5e311e07..25723f68 100644 --- a/tests/Features/Expect/pipes.php +++ b/tests/Features/Expect/pipes.php @@ -12,7 +12,7 @@ class Number public function __construct( public int $value ) { - //.. + // .. } } @@ -21,7 +21,7 @@ class Char public function __construct( public string $value ) { - //.. + // .. } } @@ -30,7 +30,7 @@ class Symbol public function __construct( public string $value ) { - //.. + // .. } } @@ -69,11 +69,11 @@ expect()->pipe('toBe', function ($next, $expected) use ($state) { assertInstanceOf(Char::class, $expected); assertEquals($this->value->value, $expected->value); - //returning nothing stops pipeline execution + // returning nothing stops pipeline execution return; } - //calling $next(); let the pipeline to keep running + // calling $next(); let the pipeline to keep running $next(); }); diff --git a/tests/Features/Expect/toBe.php b/tests/Features/Expect/toBe.php index ef2bce5a..d73760b3 100644 --- a/tests/Features/Expect/toBe.php +++ b/tests/Features/Expect/toBe.php @@ -5,7 +5,7 @@ use PHPUnit\Framework\ExpectationFailedException; expect(true)->toBeTrue()->and(false)->toBeFalse(); test('strict comparisons', function () { - $nuno = new stdClass(); + $nuno = new stdClass(); $dries = new stdClass(); expect($nuno)->toBe($nuno)->not->toBe($dries); diff --git a/tests/Features/Expect/toHaveProperties.php b/tests/Features/Expect/toHaveProperties.php index ad3da1b0..aae1303c 100644 --- a/tests/Features/Expect/toHaveProperties.php +++ b/tests/Features/Expect/toHaveProperties.php @@ -3,24 +3,24 @@ use PHPUnit\Framework\ExpectationFailedException; test('pass', function () { - $object = new stdClass(); + $object = new stdClass(); $object->name = 'Jhon'; - $object->age = 21; + $object->age = 21; expect($object)->toHaveProperties(['name', 'age']); }); test('failures', function () { - $object = new stdClass(); + $object = new stdClass(); $object->name = 'Jhon'; expect($object)->toHaveProperties(['name', 'age']); })->throws(ExpectationFailedException::class); test('not failures', function () { - $object = new stdClass(); + $object = new stdClass(); $object->name = 'Jhon'; - $object->age = 21; + $object->age = 21; expect($object)->not->toHaveProperties(['name', 'age']); })->throws(ExpectationFailedException::class); diff --git a/tests/Features/Expect/toThrow.php b/tests/Features/Expect/toThrow.php index 434ced44..b5c66abf 100644 --- a/tests/Features/Expect/toThrow.php +++ b/tests/Features/Expect/toThrow.php @@ -58,3 +58,19 @@ test('closure missing parameter', function () { test('closure missing type-hint', function () { expect(function () {})->toThrow(function ($e) {}); })->throws(InvalidArgumentException::class, 'The given closure\'s parameter must be type-hinted as the class string.'); + +it('can handle a non-defined exception', function () { + expect(function () { + throw new NonExistingException(); + })->toThrow(NonExistingException::class); +})->throws(Error::class, 'Class "NonExistingException" not found'); + +it('can handle a class not found Error', function () { + expect(function () { + throw new NonExistingException(); + })->toThrow('Class "NonExistingException" not found'); + + expect(function () { + throw new NonExistingException(); + })->toThrow(Error::class, 'Class "NonExistingException" not found'); +}); diff --git a/tests/Features/Expect/unless.php b/tests/Features/Expect/unless.php index 9f11c7ef..0dabe2bb 100644 --- a/tests/Features/Expect/unless.php +++ b/tests/Features/Expect/unless.php @@ -3,9 +3,9 @@ use PHPUnit\Framework\ExpectationFailedException; beforeEach(function () { - $this->unlessObject = new stdClass(); + $this->unlessObject = new stdClass(); $this->unlessObject->trueValue = true; - $this->unlessObject->foo = 'foo'; + $this->unlessObject->foo = 'foo'; }); it('pass', function () { diff --git a/tests/Features/Expect/when.php b/tests/Features/Expect/when.php index db9fa4f1..3b62e2f8 100644 --- a/tests/Features/Expect/when.php +++ b/tests/Features/Expect/when.php @@ -3,9 +3,9 @@ use PHPUnit\Framework\ExpectationFailedException; beforeEach(function () { - $this->whenObject = new stdClass(); + $this->whenObject = new stdClass(); $this->whenObject->trueValue = true; - $this->whenObject->foo = 'foo'; + $this->whenObject->foo = 'foo'; }); it('pass', function () { diff --git a/tests/Unit/Support/Reflection.php b/tests/Unit/Support/Reflection.php index 7ad76b0d..7e98bd76 100644 --- a/tests/Unit/Support/Reflection.php +++ b/tests/Unit/Support/Reflection.php @@ -10,7 +10,7 @@ it('gets file name from closure', function () { }); it('gets property values', function () { - $class = new class() { + $class = new class() { private $foo = 'bar'; }; diff --git a/tests/Unit/TestSuite.php b/tests/Unit/TestSuite.php index a15ad631..807594be 100644 --- a/tests/Unit/TestSuite.php +++ b/tests/Unit/TestSuite.php @@ -8,7 +8,7 @@ use Pest\TestSuite; it('does not allow to add the same test description twice', function () { $testSuite = new TestSuite(getcwd(), 'tests'); - $method = new TestCaseMethodFactory('foo', 'bar', null); + $method = new TestCaseMethodFactory('foo', 'bar', null); $testSuite->tests->set($method); $testSuite->tests->set($method); @@ -43,7 +43,7 @@ it('can return an array of all test suite filenames', function () { it('can filter the test suite filenames to those with the only method', function () { $testSuite = new TestSuite(getcwd(), 'tests'); - $testWithOnly = new TestCaseMethodFactory('a', 'b', null); + $testWithOnly = new TestCaseMethodFactory('a', 'b', null); $testWithOnly->only = true; $testSuite->tests->set($testWithOnly); @@ -61,7 +61,7 @@ it('does not filter the test suite filenames to those with the only method when $test = function () {}; - $testWithOnly = new TestCaseMethodFactory('a', 'b', null); + $testWithOnly = new TestCaseMethodFactory('a', 'b', null); $testWithOnly->only = true; $testSuite->tests->set($testWithOnly); diff --git a/tests/Visual/Help.php b/tests/Visual/Help.php index e015108f..8088f9d3 100644 --- a/tests/Visual/Help.php +++ b/tests/Visual/Help.php @@ -8,7 +8,7 @@ test('visual snapshot of help command output', function () { if (getenv('REBUILD_SNAPSHOTS')) { $outputBuffer = new BufferedOutput(); - $plugin = new Help($outputBuffer); + $plugin = new Help($outputBuffer); $plugin(); diff --git a/tests/Visual/Success.php b/tests/Visual/Success.php index 4885255e..c64344f5 100644 --- a/tests/Visual/Success.php +++ b/tests/Visual/Success.php @@ -2,7 +2,7 @@ test('visual snapshot of test suite on success', function () { $testsPath = dirname(__DIR__); - $snapshot = implode(DIRECTORY_SEPARATOR, [ + $snapshot = implode(DIRECTORY_SEPARATOR, [ $testsPath, '.snapshots', 'success.txt',