Compare commits

...

32 Commits

Author SHA1 Message Date
cc6c5bf199 docs: updates changelog 2023-09-04 00:20:57 +01:00
b88d9e8ff2 tests: update snapshots 2023-09-03 23:24:52 +01:00
0fc232bbc7 Merge pull request #934 from hungthai1401/to_have_attribute_expectation
[2.x] Add `toHaveAttribute` expectation
2023-09-03 23:18:47 +01:00
7dcd42d113 chore: prepares release 2023-09-03 21:39:21 +01:00
e79ffc6bad tests: adjusts snapshots 2023-09-03 21:36:48 +01:00
8ea425b266 Merge pull request #947 from ludoguenet/2.x
[2.x] Add `toHaveMethod` arch expectation
2023-09-03 21:32:01 +01:00
3a0f6a1d09 chore: prepares release 2023-09-03 13:37:26 +01:00
b9b90295fa Update Expectation.php
Typo
2023-09-01 18:39:37 +02:00
9dabecacbf Add toHaveMethod arch expectation 2023-09-01 18:32:40 +02:00
04fa6b6372 Merge pull request #943 from fabio-ivona/datasets-in-pest-file
fix directory separator for windows
2023-08-29 10:36:58 +01:00
a0d2856f51 docs: update changelog 2023-08-29 10:36:06 +01:00
55b9266648 release: v2.16.1 2023-08-29 10:30:36 +01:00
4313a1ef20 chore: bump dependencies 2023-08-29 10:30:28 +01:00
005ef03845 chore: bumps dependencies 2023-08-29 10:17:07 +01:00
bbac28c9f4 fix directory separator for windows 2023-08-29 11:14:23 +02:00
eb56483ba2 Merge pull request #942 from fabio-ivona/datasets-in-pest-file
[fix] missing datasets when defined in Pest.php file
2023-08-29 09:54:09 +01:00
5d6b717c9a fix missing datasets when defined in Pest.php file 2023-08-29 10:49:17 +02:00
e69899559d refactor: generic attribute 2023-08-24 15:23:13 +07:00
e6fe968d44 fix: pint 2023-08-24 14:45:11 +07:00
678898efe7 feat: toHaveAttribute expectation 2023-08-24 14:26:54 +07:00
14859a4c89 Merge pull request #930 from pestphp/feature/same-size-arg
[2.x] chore: resolve `toHaveSameSize` parameter
2023-08-23 12:01:34 +01:00
8a44d3f136 chore: resolve toHaveSameSize parameter 2023-08-23 11:28:41 +01:00
be71d6918d chore: bump dependencies 2023-08-23 10:35:06 +01:00
afb3dd459a Merge pull request #924 from hungthai1401/to_have_same_size_expectation
[2.x] Add `toHaveSameSize` expectation
2023-08-23 10:14:17 +01:00
b6e3ffafa7 fix: phpstan 2023-08-23 08:14:27 +07:00
6c95f3d8cf Merge pull request #923 from hungthai1401/inconsistent_type_have_count_exception
[2.x] Inconsistent type have count exception
2023-08-22 10:37:59 +01:00
2192373bec test: toHaveSameSize 2023-08-22 11:10:38 +07:00
dfcdaa3f8e feat: toHaveSameSize expectation 2023-08-22 11:10:25 +07:00
79bc9e677f test: toHaveCount with invalid type 2023-08-22 10:36:10 +07:00
60b615ea6a fix: inconsistent type in InvalidExpectationValue exception at toHaveCount expectation 2023-08-22 10:35:07 +07:00
8787481e40 docs: updates changelog 2023-08-21 09:53:42 +01:00
c24406259f docs: updates changelog 2023-08-21 09:51:12 +01:00
28 changed files with 338 additions and 38 deletions

View File

@ -2,6 +2,40 @@
## Unreleased
## [v2.17.0 (2023-09-04)](https://github.com/pestphp/pest/compare/v2.16.1...v2.17.0)
### Added
- `toHaveMethod` expectation ([#947](https://github.com/pestphp/pest/pull/947))
- `toHaveAttribute` expectation ([#934](https://github.com/pestphp/pest/pull/934))
## [v2.16.1 (2023-08-29)](https://github.com/pestphp/pest/compare/v2.16.0...v2.16.1)
> New changelog format starting this release.
### Added
* `toHaveSameSize` expectation by @hungthai1401 in https://github.com/pestphp/pest/pull/924, https://github.com/pestphp/pest/pull/930
### Fixed
* Inconsistent type have count exception by @hungthai1401 in https://github.com/pestphp/pest/pull/923
* Datasets defined in `Pest.php`
## [v2.16.0 (2023-08-21)](https://github.com/pestphp/pest/compare/v2.15.0...v2.16.0)
### Added
- `toBeDigits` ([#911](https://github.com/pestphp/pest/pull/911))
- `toBeCamelCase`, `toBeKebabCase`, `toBeSnakeCase`, `toBeStudlyCase`, `toHaveSnakeCaseKeys`, `toHaveKebabCaseKeys`, `toHaveCamelCaseKeys`, `toHaveStudlyCaseKeys`` ([#921](https://github.com/pestphp/pest/pull/921))
- native functions support on `arch` expectations, e.g: `expect('sleep')->toBeUsed();` ([#4](https://github.com/pestphp/pest-plugin-arch/pull/4))
### Changed
- `phpunit.xml` stub ([#915](https://github.com/pestphp/pest/pull/915))
### Fixed
- Nested sequences ([#895](https://github.com/pestphp/pest/pull/895))
## [v2.15.0 (2023-08-17)](https://github.com/pestphp/pest/compare/v2.14.1...v2.15.0)
### Added

View File

@ -18,11 +18,11 @@
],
"require": {
"php": "^8.1.0",
"brianium/paratest": "^7.2.5",
"brianium/paratest": "^7.2.6",
"nunomaduro/collision": "^7.8.1",
"nunomaduro/termwind": "^1.15.1",
"pestphp/pest-plugin": "^2.0.1",
"pestphp/pest-plugin-arch": "^2.3.1",
"pestphp/pest-plugin": "^2.1.1",
"pestphp/pest-plugin-arch": "^2.3.3",
"phpunit/phpunit": "^10.3.2"
},
"conflict": {
@ -51,8 +51,8 @@
},
"require-dev": {
"pestphp/pest-dev-tools": "^2.16.0",
"pestphp/pest-plugin-type-coverage": "^2.0.0",
"symfony/process": "^6.3.2"
"pestphp/pest-plugin-type-coverage": "^2.2.0",
"symfony/process": "^6.3.4"
},
"minimum-stability": "dev",
"prefer-stable": true,

View File

@ -78,6 +78,8 @@ final class BootFiles implements Bootstrapper
private function bootDatasets(string $testsPath): void
{
assert(strlen($testsPath) > 0);
$files = (new PhpUnitFileIterator)->getFilesAsArray($testsPath, '.php');
foreach ($files as $file) {

View File

@ -14,7 +14,7 @@ use Symfony\Component\Console\Output\OutputInterface;
/**
* @internal
*/
final class NoDirtyTestsFound extends InvalidArgumentException implements ExceptionInterface, RenderlessEditor, RenderlessTrace, Panicable
final class NoDirtyTestsFound extends InvalidArgumentException implements ExceptionInterface, Panicable, RenderlessEditor, RenderlessTrace
{
/**
* Renders the panic on the given output.

View File

@ -4,6 +4,7 @@ declare(strict_types=1);
namespace Pest;
use Attribute;
use BadMethodCallException;
use Closure;
use InvalidArgumentException;
@ -501,6 +502,19 @@ final class Expectation
);
}
/**
* Asserts that the given expectation target has a specific method.
*/
public function toHaveMethod(string $method): ArchExpectation
{
return Targeted::make(
$this,
fn (ObjectDescription $object): bool => $object->reflectionClass->hasMethod($method),
'to have method',
FileLineFinder::where(fn (string $line): bool => str_contains($line, 'class')),
);
}
/**
* Asserts that the given expectation target is enum.
*/
@ -833,4 +847,19 @@ final class Expectation
return $this;
}
/**
* Asserts that the given expectation target to have the given attribute.
*
* @param class-string<Attribute> $attribute
*/
public function toHaveAttribute(string $attribute): ArchExpectation
{
return Targeted::make(
$this,
fn (ObjectDescription $object): bool => $object->reflectionClass->getAttributes($attribute) !== [],
"to have attribute '{$attribute}'",
FileLineFinder::where(fn (string $line): bool => str_contains($line, 'class')),
);
}
}

View File

@ -4,6 +4,7 @@ declare(strict_types=1);
namespace Pest\Expectations;
use Attribute;
use Pest\Arch\Contracts\ArchExpectation;
use Pest\Arch\Expectations\Targeted;
use Pest\Arch\Expectations\ToBeUsedIn;
@ -149,6 +150,19 @@ final class OppositeExpectation
);
}
/**
* Asserts that the given expectation target does not have a specific method.
*/
public function toHaveMethod(string $method): ArchExpectation
{
return Targeted::make(
$this->original,
fn (ObjectDescription $object): bool => ! $object->reflectionClass->hasMethod($method),
'to not have method',
FileLineFinder::where(fn (string $line): bool => str_contains($line, 'class')),
);
}
/**
* Asserts that the given expectation target is not enum.
*/
@ -378,6 +392,21 @@ final class OppositeExpectation
);
}
/**
* Asserts that the given expectation target not to have the given attribute.
*
* @param class-string<Attribute> $attribute
*/
public function toHaveAttribute(string $attribute): ArchExpectation
{
return Targeted::make(
$this->original,
fn (ObjectDescription $object): bool => $object->reflectionClass->getAttributes($attribute) === [],
"to not have attribute '{$attribute}'",
FileLineFinder::where(fn (string $line): bool => str_contains($line, 'class'))
);
}
/**
* Handle dynamic method calls into the original expectation.
*

View File

@ -6,6 +6,7 @@ namespace Pest\Mixins;
use BadMethodCallException;
use Closure;
use Countable;
use DateTimeInterface;
use Error;
use InvalidArgumentException;
@ -264,7 +265,7 @@ final class Expectation
public function toHaveCount(int $count, string $message = ''): self
{
if (! is_countable($this->value) && ! is_iterable($this->value)) {
InvalidExpectationValue::expected('string');
InvalidExpectationValue::expected('countable|iterable');
}
Assert::assertCount($count, $this->value, $message);
@ -272,6 +273,23 @@ final class Expectation
return $this;
}
/**
* Asserts that the size of the value and $expected are the same.
*
* @param Countable|iterable<mixed> $expected
* @return self<TValue>
*/
public function toHaveSameSize(Countable|iterable $expected, string $message = ''): self
{
if (! is_countable($this->value) && ! is_iterable($this->value)) {
InvalidExpectationValue::expected('countable|iterable');
}
Assert::assertSameSize($expected, $this->value, $message);
return $this;
}
/**
* Asserts that the value contains the property $name.
*

View File

@ -6,10 +6,10 @@ namespace Pest;
function version(): string
{
return '2.16.0';
return '2.17.0';
}
function testDirectory(string $file = ''): string
{
return TestSuite::getInstance()->testPath.'/'.$file;
return TestSuite::getInstance()->testPath.DIRECTORY_SEPARATOR.$file;
}

View File

@ -4,6 +4,8 @@ declare(strict_types=1);
namespace Pest\Support;
use function Pest\testDirectory;
/**
* @internal
*/
@ -25,6 +27,10 @@ final class DatasetInfo
public static function scope(string $file): string
{
if (Str::endsWith($file, testDirectory('Pest.php'))) {
return dirname($file);
}
if (self::isInsideADatasetsDirectory($file)) {
return dirname($file, 2);
}

View File

@ -1,5 +1,5 @@
Pest Testing Framework 2.16.0.
Pest Testing Framework 2.17.0.
USAGE: pest <file> [options]

View File

@ -1,3 +1,3 @@
Pest Testing Framework 2.16.0.
Pest Testing Framework 2.17.0.

View File

@ -630,6 +630,11 @@
✓ failures with custom message
✓ not failures
PASS Tests\Features\Expect\toHaveAttribute
✓ class has attribute
✓ opposite class has attribute
✓ class not has attribute
PASS Tests\Features\Expect\toHaveCamelCaseKeys
✓ pass
✓ failures
@ -638,6 +643,7 @@
PASS Tests\Features\Expect\toHaveCount
✓ pass
✓ failures with invalid type
✓ failures
✓ failures with message
✓ not failures
@ -694,10 +700,12 @@
✓ it fails with message
PASS Tests\Features\Expect\toHaveMethod
pass
failures
failures with message
not failures
class has method
opposite class has method
class has method via a parent class
class has method via a trait
✓ failure when the class has no method
✓ class has no method
PASS Tests\Features\Expect\toHaveMethods
✓ pass
@ -722,6 +730,13 @@
✓ failures
✓ failures with message
✓ failures with message and Any matcher
✓ not failures
PASS Tests\Features\Expect\toHaveSameSize
✓ failures with wrong type
✓ pass
✓ failures
✓ failures with message
✓ not failures
PASS Tests\Features\Expect\toHaveSnakeCaseKeys
@ -1007,6 +1022,9 @@
✓ uses dataset with (1)
✓ uses dataset with (2)
✓ the right dataset is taken
✓ it can see datasets defined in Pest.php file with ('A')
✓ it can see datasets defined in Pest.php file with ('B')
✓ Pest.php dataset is taken
WARN Tests\Features\Skip
✓ it do not skips
@ -1296,4 +1314,4 @@
WARN Tests\Visual\Version
- visual snapshot of help command output
Tests: 2 deprecated, 4 warnings, 5 incomplete, 2 notices, 13 todos, 19 skipped, 916 passed (2190 assertions)
Tests: 2 deprecated, 4 warnings, 5 incomplete, 2 notices, 13 todos, 19 skipped, 930 passed (2200 assertions)

View File

@ -0,0 +1,18 @@
<?php
use Pest\Arch\Exceptions\ArchExpectationFailedException;
test('class has attribute')
->expect('Tests\\Fixtures\\Arch\\ToHaveAttribute\\HaveAttribute')
->toHaveAttribute('Tests\\Fixtures\\Arch\\ToHaveAttribute\\Attributes\\AsAttribute');
test('opposite class has attribute')
->throws(ArchExpectationFailedException::class)
->expect('Tests\\Fixtures\\Arch\\ToHaveAttribute\\HaveAttribute')
->not
->toHaveAttribute('Tests\\Fixtures\\Arch\\ToHaveAttribute\\Attributes\\AsAttribute');
test('class not has attribute')
->expect('Tests\\Fixtures\\Arch\\ToHaveAttribute\\NotHaveAttribute')
->not
->toHaveAttribute('Tests\\Fixtures\\Arch\\ToHaveAttribute\\Attributes\\AsAttribute');

View File

@ -1,11 +1,16 @@
<?php
use Pest\Exceptions\InvalidExpectationValue;
use PHPUnit\Framework\ExpectationFailedException;
test('pass', function () {
expect([1, 2, 3])->toHaveCount(3);
});
test('failures with invalid type', function () {
expect('foo')->toHaveCount(3);
})->throws(InvalidExpectationValue::class, 'Invalid expectation value type. Expected [countable|iterable]');
test('failures', function () {
expect([1, 2, 3])->toHaveCount(4);
})->throws(ExpectationFailedException::class);

View File

@ -1,28 +1,29 @@
<?php
use PHPUnit\Framework\ExpectationFailedException;
use Pest\Arch\Exceptions\ArchExpectationFailedException;
$object = new class
{
public function foo(): void
{
}
};
test('class has method')
->expect('Tests\Fixtures\Arch\ToHaveMethod\HasMethod\HasMethod')
->toHaveMethod('foo');
test('pass', function () use ($object) {
expect($object)->toHaveMethod('foo')
->and($object)->toHaveMethod('foo')
->and($object)->not->toHaveMethod('fooNull');
});
test('opposite class has method')
->throws(ArchExpectationFailedException::class)
->expect('Tests\Fixtures\Arch\ToHaveMethod\HasMethod\HasMethod')
->not->toHaveMethod('foo');
test('failures', function () use ($object) {
expect($object)->toHaveMethod('bar');
})->throws(ExpectationFailedException::class);
test('class has method via a parent class')
->expect('Tests\Fixtures\Arch\ToHaveMethod\HasMethod\HasMethodViaParent')
->toHaveMethod('foo');
test('failures with message', function () use ($object) {
expect($object)->toHaveMethod(name: 'bar', message: 'oh no!');
})->throws(ExpectationFailedException::class, 'oh no!');
test('class has method via a trait')
->expect('Tests\Fixtures\Arch\ToHaveMethod\HasMethod\HasMethodViaTrait')
->toHaveMethod('foo');
test('not failures', function () use ($object) {
expect($object)->not->toHaveMethod('foo');
})->throws(ExpectationFailedException::class);
test('failure when the class has no method')
->throws(ArchExpectationFailedException::class)
->expect('Tests\Fixtures\Arch\ToHaveMethod\HasNoMethod\HasNoMethodClass')
->toHaveMethod('foo');
test('class has no method')
->expect('Tests\Fixtures\Arch\ToHaveMethod\HasNoMethod\HasNoMethodClass')
->not->toHaveMethod('foo');

View File

@ -0,0 +1,24 @@
<?php
use Pest\Exceptions\InvalidExpectationValue;
use PHPUnit\Framework\ExpectationFailedException;
test('failures with wrong type', function () {
expect('foo')->toHaveSameSize([1]);
})->throws(InvalidExpectationValue::class, 'Invalid expectation value type. Expected [countable|iterable].');
test('pass', function () {
expect([1, 2, 3])->toHaveSameSize([4, 5, 6]);
});
test('failures', function () {
expect([1, 2, 3])->toHaveSameSize([1]);
})->throws(ExpectationFailedException::class);
test('failures with message', function () {
expect([1, 2, 3])->toHaveSameSize([1], 'oh no!');
})->throws(ExpectationFailedException::class, 'oh no!');
test('not failures', function () {
expect([1, 2, 3])->not->toHaveSameSize([1]);
});

View File

@ -10,3 +10,12 @@ test('uses dataset', function ($value) use ($state) {
test('the right dataset is taken', function () use ($state) {
expect($state->text)->toBe('12');
});
it('can see datasets defined in Pest.php file', function (string $value) use ($state) {
$state->text .= $value;
expect(true)->toBe(true);
})->with('dataset_in_pest_file');
test('Pest.php dataset is taken', function () use ($state) {
expect($state->text)->toBe('12AB');
});

View File

@ -0,0 +1,12 @@
<?php
declare(strict_types=1);
namespace Tests\Fixtures\Arch\ToHaveAttribute\Attributes;
use Attribute;
#[Attribute()]
class AsAttribute
{
}

View File

@ -0,0 +1,12 @@
<?php
declare(strict_types=1);
namespace Tests\Fixtures\Arch\ToHaveAttribute\HaveAttribute;
use Tests\Fixtures\Arch\ToHaveAttribute\Attributes\AsAttribute;
#[AsAttribute]
class HaveAttributeClass
{
}

View File

@ -0,0 +1,9 @@
<?php
declare(strict_types=1);
namespace Tests\Fixtures\Arch\ToHaveAttribute\NotHaveAttribute;
class NotHaveAttributeClass
{
}

View File

@ -0,0 +1,13 @@
<?php
declare(strict_types=1);
namespace Tests\Fixtures\Arch\ToHaveMethod\HasMethod;
class HasMethod
{
public function foo(): void
{
}
}

View File

@ -0,0 +1,13 @@
<?php
declare(strict_types=1);
namespace Tests\Fixtures\Arch\ToHaveMethod\HasMethod;
trait HasMethodTrait
{
public function foo(): void
{
}
}

View File

@ -0,0 +1,10 @@
<?php
declare(strict_types=1);
namespace Tests\Fixtures\Arch\ToHaveMethod\HasMethod;
class HasMethodViaParent extends ParentHasMethodClass
{
//
}

View File

@ -0,0 +1,10 @@
<?php
declare(strict_types=1);
namespace Tests\Fixtures\Arch\ToHaveMethod\HasMethod;
class HasMethodViaTrait
{
use HasMethodTrait;
}

View File

@ -0,0 +1,13 @@
<?php
declare(strict_types=1);
namespace Tests\Fixtures\Arch\ToHaveMethod\HasMethod;
class ParentHasMethodClass
{
public function foo(): void
{
}
}

View File

@ -0,0 +1,13 @@
<?php
declare(strict_types=1);
namespace Tests\Fixtures\Arch\ToHaveMethod\HasNoMethod;
class HasNoMethodClass
{
public function bar(): void
{
}
}

View File

@ -37,3 +37,5 @@ function helper_returns_string()
{
return 'string';
}
dataset('dataset_in_pest_file', ['A', 'B']);

View File

@ -16,7 +16,7 @@ $run = function () {
test('parallel', function () use ($run) {
expect($run('--exclude-group=integration'))
->toContain('Tests: 1 deprecated, 4 warnings, 5 incomplete, 2 notices, 13 todos, 15 skipped, 905 passed (2175 assertions)')
->toContain('Tests: 1 deprecated, 4 warnings, 5 incomplete, 2 notices, 13 todos, 15 skipped, 919 passed (2185 assertions)')
->toContain('Parallel: 3 processes');
})->skipOnWindows();