Merge branch 'master' into feat/retry

This commit is contained in:
Nuno Maduro
2021-12-05 17:44:20 +00:00
committed by GitHub
27 changed files with 1561 additions and 946 deletions

View File

@ -96,11 +96,20 @@
✓ more than two datasets with (2) / (4) / (5)
✓ more than two datasets with (2) / (4) / (6)
✓ more than two datasets did the job right
✓ it can resolve a dataset after the test case is available with (Closure Object (...))
✓ it can resolve a dataset after the test case is available with (Closure Object (...)) #1
✓ it can resolve a dataset after the test case is available with (Closure Object (...)) #2
✓ it can resolve a dataset after the test case is available with shared yield sets with (Closure Object (...)) #1
✓ it can resolve a dataset after the test case is available with shared yield sets with (Closure Object (...)) #2
✓ it can resolve a dataset after the test case is available with shared array sets with (Closure Object (...)) #1
✓ it can resolve a dataset after the test case is available with shared array sets with (Closure Object (...)) #2
✓ it resolves a potential bound dataset logically with ('foo', Closure Object (...))
✓ it resolves a potential bound dataset logically even when the closure comes first with (Closure Object (...), 'bar')
✓ it will not resolve a closure if it is type hinted as a closure with (Closure Object (...)) #1
✓ it will not resolve a closure if it is type hinted as a closure with (Closure Object (...)) #2
✓ it will not resolve a closure if it is type hinted as a callable with (Closure Object (...)) #1
✓ it will not resolve a closure if it is type hinted as a callable with (Closure Object (...)) #2
✓ it can correctly resolve a bound dataset that returns an array with (Closure Object (...))
✓ it can correctly resolve a bound dataset that returns an array but wants to be spread with (Closure Object (...))
PASS Tests\Features\Exceptions
✓ it gives access the the underlying expectException
@ -177,6 +186,17 @@
PASS Tests\Features\Expect\not
✓ not property calls
PASS Tests\Features\Expect\pipe
✓ pipe is applied and can stop pipeline
✓ interceptor works with negated expectation
✓ pipe works with negated expectation
✓ pipe is run and can let the pipeline keep going
✓ intercept is applied
✓ intercept stops the pipeline
✓ interception is called only when filter is met
✓ intercept can be filtered with a closure
✓ intercept can add new parameters to the expectation
PASS Tests\Features\Expect\ray
✓ ray calls do not fail when ray is not installed
@ -720,5 +740,5 @@
✓ it is a test
✓ it uses correct parent class
Tests: 4 incompleted, 9 skipped, 478 passed
Tests: 4 incompleted, 9 skipped, 487 passed

View File

@ -1,9 +1,9 @@
<?php
use Pest\Datasets;
use Pest\Exceptions\DatasetAlreadyExist;
use Pest\Exceptions\DatasetDoesNotExist;
use Pest\Plugin;
use Pest\Repositories\DatasetsRepository;
beforeEach(function () {
$this->foo = 'bar';
@ -13,28 +13,28 @@ it('throws exception if dataset does not exist', function () {
$this->expectException(DatasetDoesNotExist::class);
$this->expectExceptionMessage("A dataset with the name `first` does not exist. You can create it using `dataset('first', ['a', 'b']);`.");
Datasets::resolve('foo', ['first']);
DatasetsRepository::resolve('foo', ['first']);
});
it('throws exception if dataset already exist', function () {
Datasets::set('second', [[]]);
DatasetsRepository::set('second', [[]]);
$this->expectException(DatasetAlreadyExist::class);
$this->expectExceptionMessage('A dataset with the name `second` already exist.');
Datasets::set('second', [[]]);
DatasetsRepository::set('second', [[]]);
});
it('sets closures', function () {
Datasets::set('foo', function () {
DatasetsRepository::set('foo', function () {
yield [1];
});
expect(Datasets::resolve('foo', ['foo']))->toBe(['foo with (1)' => [1]]);
expect(DatasetsRepository::resolve('foo', ['foo']))->toBe(['foo with (1)' => [1]]);
});
it('sets arrays', function () {
Datasets::set('bar', [[2]]);
DatasetsRepository::set('bar', [[2]]);
expect(Datasets::resolve('bar', ['bar']))->toBe(['bar with (2)' => [2]]);
expect(DatasetsRepository::resolve('bar', ['bar']))->toBe(['bar with (2)' => [2]]);
});
it('gets bound to test case object', function () {
@ -234,6 +234,7 @@ it('can resolve a dataset after the test case is available', function ($result)
expect($result)->toBe('bar');
})->with([
function () { return $this->foo; },
[function () { return $this->foo; }],
]);
it('can resolve a dataset after the test case is available with shared yield sets', function ($result) {
@ -243,3 +244,43 @@ it('can resolve a dataset after the test case is available with shared yield set
it('can resolve a dataset after the test case is available with shared array sets', function ($result) {
expect($result)->toBeInt()->toBeLessThan(3);
})->with('bound.array');
it('resolves a potential bound dataset logically', function ($foo, $bar) {
expect($foo)->toBe('foo');
expect($bar())->toBe('bar');
})->with([
['foo', function () { return 'bar'; }], // This should be passed as a closure because we've passed multiple arguments
]);
it('resolves a potential bound dataset logically even when the closure comes first', function ($foo, $bar) {
expect($foo())->toBe('foo');
expect($bar)->toBe('bar');
})->with([
[function () { return 'foo'; }, 'bar'], // This should be passed as a closure because we've passed multiple arguments
]);
it('will not resolve a closure if it is type hinted as a closure', function (Closure $data) {
expect($data())->toBeString();
})->with([
function () { return 'foo'; },
function () { return 'bar'; },
]);
it('will not resolve a closure if it is type hinted as a callable', function (callable $data) {
expect($data())->toBeString();
})->with([
function () { return 'foo'; },
function () { return 'bar'; },
]);
it('can correctly resolve a bound dataset that returns an array', function (array $data) {
expect($data)->toBe(['foo', 'bar', 'baz']);
})->with([
function () { return ['foo', 'bar', 'baz']; },
]);
it('can correctly resolve a bound dataset that returns an array but wants to be spread', function (string $foo, string $bar, string $baz) {
expect([$foo, $bar, $baz])->toBe(['foo', 'bar', 'baz']);
})->with([
function () { return ['foo', 'bar', 'baz']; },
]);

View File

@ -0,0 +1,257 @@
<?php
declare(strict_types=1);
use function PHPUnit\Framework\assertEquals;
use function PHPUnit\Framework\assertEqualsIgnoringCase;
use function PHPUnit\Framework\assertInstanceOf;
use function PHPUnit\Framework\assertSame;
class Number
{
public function __construct(
public int $value
) {
//..
}
}
class Char
{
public function __construct(
public string $value
) {
//..
}
}
class Symbol
{
public function __construct(
public string $value
) {
//..
}
}
class State
{
public array $runCount = [];
public array $appliedCount = [];
public function __construct()
{
$this->reset();
}
public function reset(): void
{
$this->appliedCount = $this->runCount = [
'char' => 0,
'number' => 0,
'wildcard' => 0,
'symbol' => 0,
];
}
}
$state = new State();
/*
* Overrides toBe to assert two Characters are the same
*/
expect()->pipe('toBe', function ($next, $expected) use ($state) {
$state->runCount['char']++;
if ($this->value instanceof Char) {
$state->appliedCount['char']++;
assertInstanceOf(Char::class, $expected);
assertEquals($this->value->value, $expected->value);
//returning nothing stops pipeline execution
return;
}
//calling $next(); let the pipeline to keep running
$next();
});
/*
* Overrides toBe to assert two Number objects are the same
*/
expect()->intercept('toBe', Number::class, function ($expected) use ($state) {
$state->runCount['number']++;
$state->appliedCount['number']++;
assertInstanceOf(Number::class, $expected);
assertEquals($this->value->value, $expected->value);
});
/*
* Overrides toBe to assert all integers are allowed if value is a wildcard (*)
*/
expect()->intercept('toBe', fn ($value, $expected) => $value === '*' && is_numeric($expected), function ($expected) use ($state) {
$state->runCount['wildcard']++;
$state->appliedCount['wildcard']++;
});
/*
* Overrides toBe to assert to Symbols are the same
*/
expect()->pipe('toBe', function ($next, $expected) use ($state) {
$state->runCount['symbol']++;
if ($this->value instanceof Symbol) {
$state->appliedCount['symbol']++;
assertInstanceOf(Symbol::class, $expected);
assertEquals($this->value->value, $expected->value);
return;
}
$next();
});
/*
* Overrides toBe to allow ignoring case when checking strings
*/
expect()->intercept('toBe', fn ($value) => is_string($value), function ($expected, $ignoreCase = false) {
if ($ignoreCase) {
assertEqualsIgnoringCase($expected, $this->value);
} else {
assertSame($expected, $this->value);
}
});
test('pipe is applied and can stop pipeline', function () use ($state) {
$char = new Char('A');
$state->reset();
expect($char)->toBe(new Char('A'))
->and($state)
->runCount->toMatchArray([
'char' => 1,
'number' => 0,
'wildcard' => 0,
'symbol' => 0,
])
->appliedCount->toMatchArray([
'char' => 1,
'number' => 0,
'wildcard' => 0,
'symbol' => 0,
]);
});
test('pipe is run and can let the pipeline keep going', function () use ($state) {
$state->reset();
expect(3)->toBe(3)
->and($state)
->runCount->toMatchArray([
'char' => 1,
'number' => 0,
'wildcard' => 0,
'symbol' => 1,
])
->appliedCount->toMatchArray([
'char' => 0,
'number' => 0,
'wildcard' => 0,
'symbol' => 0,
]);
});
test('pipe works with negated expectation', function () use ($state) {
$char = new Char('A');
$state->reset();
expect($char)->not->toBe(new Char('B'))
->and($state)
->runCount->toMatchArray([
'char' => 1,
'number' => 0,
'wildcard' => 0,
'symbol' => 0,
])
->appliedCount->toMatchArray([
'char' => 1,
'number' => 0,
'wildcard' => 0,
'symbol' => 0,
]);
});
test('interceptor is applied', function () use ($state) {
$number = new Number(1);
$state->reset();
expect($number)->toBe(new Number(1))
->and($state)
->runCount->toHaveKey('number', 1)
->appliedCount->toHaveKey('number', 1);
});
test('interceptor stops the pipeline', function () use ($state) {
$number = new Number(1);
$state->reset();
expect($number)->toBe(new Number(1))
->and($state)
->runCount->toMatchArray([
'char' => 1,
'number' => 1,
'wildcard' => 0,
'symbol' => 0,
])
->appliedCount->toMatchArray([
'char' => 0,
'number' => 1,
'wildcard' => 0,
'symbol' => 0,
]);
});
test('interceptor is called only when filter is met', function () use ($state) {
$state->reset();
expect(1)->toBe(1)
->and($state)
->runCount->toHaveKey('number', 0)
->appliedCount->toHaveKey('number', 0);
});
test('interceptor can be filtered with a closure', function () use ($state) {
$state->reset();
expect('*')->toBe(1)
->and($state)
->runCount->toHaveKey('wildcard', 1)
->appliedCount->toHaveKey('wildcard', 1);
});
test('interceptor can be filter the expected parameter as well', function () use ($state) {
$state->reset();
expect('*')->toBe('*')
->and($state)
->runCount->toHaveKey('wildcard', 0)
->appliedCount->toHaveKey('wildcard', 0);
});
test('interceptor works with negated expectation', function () {
$char = new Number(1);
expect($char)->not->toBe(new Char('B'));
});
test('intercept can add new parameters to the expectation', function () {
$ignoreCase = true;
expect('Foo')->toBe('foo', $ignoreCase);
});

View File

@ -1,9 +1,9 @@
<?php
use Pest\Datasets;
use Pest\Repositories\DatasetsRepository;
it('show only the names of named datasets in their description', function () {
$descriptions = array_keys(Datasets::resolve('test description', [
$descriptions = array_keys(DatasetsRepository::resolve('test description', [
[
'one' => [1],
'two' => [[2]],
@ -15,7 +15,7 @@ it('show only the names of named datasets in their description', function () {
});
it('show the actual dataset of non-named datasets in their description', function () {
$descriptions = array_keys(Datasets::resolve('test description', [
$descriptions = array_keys(DatasetsRepository::resolve('test description', [
[
[1],
[[2]],
@ -27,7 +27,7 @@ it('show the actual dataset of non-named datasets in their description', functio
});
it('show only the names of multiple named datasets in their description', function () {
$descriptions = array_keys(Datasets::resolve('test description', [
$descriptions = array_keys(DatasetsRepository::resolve('test description', [
[
'one' => [1],
'two' => [[2]],
@ -45,7 +45,7 @@ it('show only the names of multiple named datasets in their description', functi
});
it('show the actual dataset of multiple non-named datasets in their description', function () {
$descriptions = array_keys(Datasets::resolve('test description', [
$descriptions = array_keys(DatasetsRepository::resolve('test description', [
[
[1],
[[2]],
@ -63,7 +63,7 @@ it('show the actual dataset of multiple non-named datasets in their description'
});
it('show the correct description for mixed named and not-named datasets', function () {
$descriptions = array_keys(Datasets::resolve('test description', [
$descriptions = array_keys(DatasetsRepository::resolve('test description', [
[
'one' => [1],
[[2]],