mirror of
https://github.com/pestphp/pest.git
synced 2026-03-06 15:57:21 +01:00
Merge branch 'pipes-and-interceptors' into next-1
# Conflicts: # src/Concerns/Extendable.php # src/CoreExpectation.php # src/Expectation.php # src/Support/ExpectationPipeline.php # src/Support/Extendable.php
This commit is contained in:
@ -177,6 +177,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 +731,5 @@
|
||||
✓ it is a test
|
||||
✓ it uses correct parent class
|
||||
|
||||
Tests: 4 incompleted, 9 skipped, 478 passed
|
||||
Tests: 4 incompleted, 9 skipped, 487 passed
|
||||
|
||||
@ -12,7 +12,8 @@ beforeEach(function () {
|
||||
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::get('first');
|
||||
|
||||
Datasets::resolve('foo', ['first']);
|
||||
});
|
||||
|
||||
it('throws exception if dataset already exist', function () {
|
||||
@ -27,13 +28,13 @@ it('sets closures', function () {
|
||||
yield [1];
|
||||
});
|
||||
|
||||
expect(iterator_to_array(Datasets::get('foo')()))->toBe([[1]]);
|
||||
expect(Datasets::resolve('foo', ['foo']))->toBe(['foo with (1)' => [1]]);
|
||||
});
|
||||
|
||||
it('sets arrays', function () {
|
||||
Datasets::set('bar', [[2]]);
|
||||
|
||||
expect(Datasets::get('bar'))->toBe([[2]]);
|
||||
expect(Datasets::resolve('bar', ['bar']))->toBe(['bar with (2)' => [2]]);
|
||||
});
|
||||
|
||||
it('gets bound to test case object', function () {
|
||||
@ -52,6 +53,7 @@ $datasets = [[1], [2]];
|
||||
|
||||
test('lazy datasets', function ($text) use ($state, $datasets) {
|
||||
$state->text .= $text;
|
||||
|
||||
expect(in_array([$text], $datasets))->toBe(true);
|
||||
})->with($datasets);
|
||||
|
||||
|
||||
240
tests/Features/Expect/pipe.php
Normal file
240
tests/Features/Expect/pipe.php
Normal file
@ -0,0 +1,240 @@
|
||||
<?php
|
||||
|
||||
use function PHPUnit\Framework\assertEquals;
|
||||
use function PHPUnit\Framework\assertEqualsIgnoringCase;
|
||||
use function PHPUnit\Framework\assertInstanceOf;
|
||||
use function PHPUnit\Framework\assertIsNumeric;
|
||||
use function PHPUnit\Framework\assertSame;
|
||||
|
||||
class Number
|
||||
{
|
||||
public $value;
|
||||
|
||||
public function __construct($value)
|
||||
{
|
||||
$this->value = $value;
|
||||
}
|
||||
}
|
||||
|
||||
class Character
|
||||
{
|
||||
public $value;
|
||||
|
||||
public function __construct($value)
|
||||
{
|
||||
$this->value = $value;
|
||||
}
|
||||
}
|
||||
|
||||
class Symbol
|
||||
{
|
||||
public $value;
|
||||
|
||||
public function __construct($value)
|
||||
{
|
||||
$this->value = $value;
|
||||
}
|
||||
}
|
||||
|
||||
class State
|
||||
{
|
||||
public $runCount = [];
|
||||
public $appliedCount = [];
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->reset();
|
||||
}
|
||||
|
||||
public function reset(): void
|
||||
{
|
||||
$this->runCount = [
|
||||
'character' => 0,
|
||||
'number' => 0,
|
||||
'wildcard' => 0,
|
||||
'symbol' => 0,
|
||||
];
|
||||
|
||||
$this->appliedCount = [
|
||||
'character' => 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['character']++;
|
||||
|
||||
if ($this->value instanceof Character) {
|
||||
$state->appliedCount['character']++;
|
||||
assertInstanceOf(Character::class, $expected);
|
||||
assertEquals($this->value->value, $expected->value);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$next();
|
||||
});
|
||||
|
||||
/*
|
||||
* Overrides toBe to assert two Numbers are the same
|
||||
*/
|
||||
expect()->intercept('toBe', Number::class, function ($expected) use ($state) {
|
||||
$state->runCount['number']++;
|
||||
$state->appliedCount['number']++;
|
||||
assertEquals($this->value->value, $expected->value);
|
||||
});
|
||||
|
||||
/*
|
||||
* Overrides toBe to assert all integers are allowed if value is an '*'
|
||||
*/
|
||||
expect()->intercept('toBe', function ($value) {
|
||||
return $value === '*';
|
||||
}, function ($expected) use ($state) {
|
||||
$state->runCount['wildcard']++;
|
||||
$state->appliedCount['wildcard']++;
|
||||
assertIsNumeric($expected);
|
||||
});
|
||||
|
||||
/*
|
||||
* Overrides toBe to assert two 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 check strings ignoring case
|
||||
*/
|
||||
expect()->intercept('toBe', function ($value) {
|
||||
return 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) {
|
||||
$letter = new Character('A');
|
||||
|
||||
$state->reset();
|
||||
|
||||
expect($letter)->toBe(new Character('A'))
|
||||
->and($state)
|
||||
->runCount->toMatchArray([
|
||||
'character' => 1,
|
||||
'number' => 0,
|
||||
'wildcard' => 0,
|
||||
'symbol' => 0,
|
||||
])
|
||||
->appliedCount->toMatchArray([
|
||||
'character' => 1,
|
||||
'number' => 0,
|
||||
'wildcard' => 0,
|
||||
'symbol' => 0,
|
||||
]);
|
||||
});
|
||||
|
||||
test('interceptor works with negated expectation', function () {
|
||||
$letter = new Number(1);
|
||||
|
||||
expect($letter)->not->toBe(new Character('B'));
|
||||
});
|
||||
|
||||
test('pipe works with negated expectation', function () {
|
||||
$letter = new Character('A');
|
||||
|
||||
expect($letter)->not->toBe(new Character('B'));
|
||||
});
|
||||
|
||||
test('pipe is run and can let the pipeline keep going', function () use ($state) {
|
||||
$state->reset();
|
||||
|
||||
expect(3)->toBe(3)
|
||||
->and($state)
|
||||
->runCount->toMatchArray([
|
||||
'character' => 1,
|
||||
'number' => 0,
|
||||
'wildcard' => 0,
|
||||
'symbol' => 1,
|
||||
])
|
||||
->appliedCount->toMatchArray([
|
||||
'character' => 0,
|
||||
'number' => 0,
|
||||
'wildcard' => 0,
|
||||
'symbol' => 0,
|
||||
]);
|
||||
});
|
||||
|
||||
test('intercept 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('intercept stops the pipeline', function () use ($state) {
|
||||
$number = new Number(1);
|
||||
|
||||
$state->reset();
|
||||
|
||||
expect($number)->toBe(new Number(1))
|
||||
->and($state)
|
||||
->runCount->toMatchArray([
|
||||
'character' => 1,
|
||||
'number' => 1,
|
||||
'wildcard' => 0,
|
||||
'symbol' => 0,
|
||||
])
|
||||
->appliedCount->toMatchArray([
|
||||
'character' => 0,
|
||||
'number' => 1,
|
||||
'wildcard' => 0,
|
||||
'symbol' => 0,
|
||||
]);
|
||||
});
|
||||
|
||||
test('interception 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('intercept 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('intercept can add new parameters to the expectation', function () {
|
||||
expect('Foo')->toBe('foo', true);
|
||||
});
|
||||
@ -7,7 +7,7 @@ namespace Tests\CustomTestCase;
|
||||
use function PHPUnit\Framework\assertTrue;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class CustomTestCase extends TestCase
|
||||
abstract class CustomTestCase extends TestCase
|
||||
{
|
||||
public function assertCustomTrue()
|
||||
{
|
||||
|
||||
@ -2,53 +2,55 @@
|
||||
|
||||
use Pest\Exceptions\DatasetMissing;
|
||||
use Pest\Exceptions\TestAlreadyExist;
|
||||
use Pest\Factories\TestCaseFactory;
|
||||
use Pest\Factories\TestCaseMethodFactory;
|
||||
use Pest\Plugins\Environment;
|
||||
use Pest\TestSuite;
|
||||
|
||||
it('does not allow to add the same test description twice', function () {
|
||||
$testSuite = new TestSuite(getcwd(), 'tests');
|
||||
$test = function () {};
|
||||
$testSuite->tests->set(new TestCaseFactory(__FILE__, 'foo', $test));
|
||||
$testSuite->tests->set(new TestCaseFactory(__FILE__, 'foo', $test));
|
||||
$method = new TestCaseMethodFactory('foo', 'bar', null);
|
||||
|
||||
$testSuite->tests->set($method);
|
||||
$testSuite->tests->set($method);
|
||||
})->throws(
|
||||
TestAlreadyExist::class,
|
||||
sprintf('A test with the description `%s` already exist in the filename `%s`.', 'foo', __FILE__),
|
||||
sprintf('A test with the description `%s` already exist in the filename `%s`.', 'bar', 'foo'),
|
||||
);
|
||||
|
||||
it('alerts users about tests with arguments but no input', function () {
|
||||
$testSuite = new TestSuite(getcwd(), 'tests');
|
||||
$test = function (int $arg) {};
|
||||
$testSuite->tests->set(new TestCaseFactory(__FILE__, 'foo', $test));
|
||||
|
||||
$method = new TestCaseMethodFactory('foo', 'bar', function (int $arg) {});
|
||||
|
||||
$testSuite->tests->set($method);
|
||||
})->throws(
|
||||
DatasetMissing::class,
|
||||
sprintf("A test with the description '%s' has %d argument(s) ([%s]) and no dataset(s) provided in %s", 'foo', 1, 'int $arg', __FILE__),
|
||||
sprintf("A test with the description '%s' has %d argument(s) ([%s]) and no dataset(s) provided in %s", 'bar', 1, 'int $arg', 'foo'),
|
||||
);
|
||||
|
||||
it('can return an array of all test suite filenames', function () {
|
||||
$testSuite = TestSuite::getInstance(getcwd(), 'tests');
|
||||
$test = function () {};
|
||||
$testSuite->tests->set(new TestCaseFactory(__FILE__, 'foo', $test));
|
||||
$testSuite->tests->set(new TestCaseFactory(__FILE__, 'bar', $test));
|
||||
|
||||
$testSuite->tests->set(new TestCaseMethodFactory('a', 'b', null));
|
||||
$testSuite->tests->set(new TestCaseMethodFactory('c', 'd', null));
|
||||
|
||||
expect($testSuite->tests->getFilenames())->toEqual([
|
||||
__FILE__,
|
||||
__FILE__,
|
||||
'a',
|
||||
'c',
|
||||
]);
|
||||
});
|
||||
|
||||
it('can filter the test suite filenames to those with the only method', function () {
|
||||
$testSuite = new TestSuite(getcwd(), 'tests');
|
||||
$test = function () {};
|
||||
|
||||
$testWithOnly = new TestCaseFactory(__FILE__, 'foo', $test);
|
||||
$testWithOnly = new TestCaseMethodFactory('a', 'b', null);
|
||||
$testWithOnly->only = true;
|
||||
$testSuite->tests->set($testWithOnly);
|
||||
|
||||
$testSuite->tests->set(new TestCaseFactory('Baz/Bar/Boo.php', 'bar', $test));
|
||||
$testSuite->tests->set(new TestCaseMethodFactory('c', 'd', null));
|
||||
|
||||
expect($testSuite->tests->getFilenames())->toEqual([
|
||||
__FILE__,
|
||||
'a',
|
||||
]);
|
||||
});
|
||||
|
||||
@ -59,15 +61,15 @@ it('does not filter the test suite filenames to those with the only method when
|
||||
|
||||
$test = function () {};
|
||||
|
||||
$testWithOnly = new TestCaseFactory(__FILE__, 'foo', $test);
|
||||
$testWithOnly = new TestCaseMethodFactory('a', 'b', null);
|
||||
$testWithOnly->only = true;
|
||||
$testSuite->tests->set($testWithOnly);
|
||||
|
||||
$testSuite->tests->set(new TestCaseFactory('Baz/Bar/Boo.php', 'bar', $test));
|
||||
$testSuite->tests->set(new TestCaseMethodFactory('c', 'd', null));
|
||||
|
||||
expect($testSuite->tests->getFilenames())->toEqual([
|
||||
__FILE__,
|
||||
'Baz/Bar/Boo.php',
|
||||
'a',
|
||||
'c',
|
||||
]);
|
||||
|
||||
Environment::name($previousEnvironment);
|
||||
|
||||
Reference in New Issue
Block a user