Skip to content

Commit

Permalink
Merge pull request #60 from gsteel/validation-group-tests
Browse files Browse the repository at this point in the history
Regression for input filter collections
  • Loading branch information
Ocramius committed Jul 25, 2022
2 parents 9b0c514 + 73d7a19 commit 89dab1f
Show file tree
Hide file tree
Showing 4 changed files with 292 additions and 5 deletions.
3 changes: 0 additions & 3 deletions psalm-baseline.xml
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,6 @@
</NonInvariantDocblockPropertyType>
</file>
<file src="src/BaseInputFilter.php">
<DocblockTypeContradiction occurrences="1">
<code>! is_string($name)</code>
</DocblockTypeContradiction>
<InvalidPropertyAssignmentValue occurrences="1">
<code>$this-&gt;inputs</code>
</InvalidPropertyAssignmentValue>
Expand Down
3 changes: 1 addition & 2 deletions src/BaseInputFilter.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
use function is_array;
use function is_int;
use function is_object;
use function is_string;
use function sprintf;

class BaseInputFilter implements
Expand Down Expand Up @@ -497,7 +496,7 @@ public function getMessages()
protected function validateValidationGroup(array $inputs)
{
foreach ($inputs as $name) {
if (! is_string($name) || ! array_key_exists($name, $this->inputs)) {
if (! array_key_exists($name, $this->inputs)) {
throw new Exception\InvalidArgumentException(sprintf(
'setValidationGroup() expects a list of valid input names; "%s" was not found',
(string) $name
Expand Down
213 changes: 213 additions & 0 deletions test/ValidationGroup/InputFilterCollectionsValidationGroupTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
<?php

declare(strict_types=1);

namespace LaminasTest\InputFilter\ValidationGroup;

use Laminas\InputFilter\CollectionInputFilter;
use Laminas\InputFilter\Input;
use Laminas\InputFilter\InputFilter;
use PHPUnit\Framework\TestCase;

use const PHP_VERSION_ID;

final class InputFilterCollectionsValidationGroupTest extends TestCase
{
private InputFilter $inputFilter;

protected function setUp(): void
{
parent::setUp();

$collection = new CollectionInputFilter();
$collection->setIsRequired(true);

$first = new Input('first');
$first->setRequired(true);
$second = new Input('second');
$second->setRequired(true);

$nestedFilter = new InputFilter();
$nestedFilter->add($first);
$nestedFilter->add($second);
$collection->setInputFilter($nestedFilter);

$this->inputFilter = new InputFilter();
$this->inputFilter->add($collection, 'stuff');
}

/** @return array<string, array{0: int|null}> */
public function collectionCountProvider(): array
{
return [
'Collection Count: None' => [null],
'Collection Count: One' => [1],
'Collection Count: Two' => [2],
'Collection Count: Three' => [3],
'Collection Count: Four' => [4],
];
}

private function setCollectionCount(?int $count): void
{
if ($count === null) {
return;
}

$collection = $this->inputFilter->get('stuff');
self::assertInstanceOf(CollectionInputFilter::class, $collection);
$collection->setCount($count);
}

/** @dataProvider collectionCountProvider */
public function testIncompleteDataFailsValidation(?int $count): void
{
$this->setCollectionCount($count);
$this->inputFilter->setData([
'stuff' => [
['first' => 'Foo'],
],
]);
self::assertFalse($this->inputFilter->isValid());
}

/** @dataProvider collectionCountProvider */
public function testCompleteDataPassesValidation(?int $count): void
{
$this->setCollectionCount($count);
$this->inputFilter->setData([
'stuff' => [
['first' => 'Foo', 'second' => 'Bar'],
['first' => 'Foo', 'second' => 'Bar'],
['first' => 'Foo', 'second' => 'Bar'],
['first' => 'Foo', 'second' => 'Bar'],
],
]);

self::assertTrue($this->inputFilter->isValid());
}

/** @dataProvider collectionCountProvider */
public function testValidationFailsForCollectionItemValidity(?int $count): void
{
$this->setCollectionCount($count);
$this->inputFilter->setData([
'stuff' => [
['first' => 'Foo', 'second' => 'Bar'],
['first' => '', 'second' => 'Bar'],
['first' => 'Foo', 'second' => ''],
['first' => '', 'second' => ''],
],
]);

self::assertFalse($this->inputFilter->isValid());
}

/** @dataProvider collectionCountProvider */
public function testValidationGroupWithCollectionInputFilter(?int $count): void
{
$this->setCollectionCount($count);
$collection = $this->inputFilter->get('stuff');
self::assertInstanceOf(CollectionInputFilter::class, $collection);
$collection->getInputFilter()->setValidationGroup('first');

$this->inputFilter->setData([
'stuff' => [
['first' => 'Foo'],
['first' => 'Foo'],
['first' => 'Foo'],
['first' => 'Foo'],
],
]);

self::assertTrue($this->inputFilter->isValid());
}

/** @dataProvider collectionCountProvider */
public function testValidationGroupViaCollection(?int $count): void
{
$this->setCollectionCount($count);
$collection = $this->inputFilter->get('stuff');
self::assertInstanceOf(CollectionInputFilter::class, $collection);
/** @psalm-suppress InvalidArgument */
$collection->setValidationGroup([
0 => 'first',
1 => 'second',
2 => 'first',
3 => 'first',
]);

$this->inputFilter->setData([
'stuff' => [
['first' => 'Foo'],
['second' => 'Foo'],
['first' => 'Foo'],
['first' => 'Foo'],
],
]);

self::assertTrue($this->inputFilter->isValid());
}

/**
* This test documents existing behaviour - the validation group must be set for elements 0 through 3
*
* @dataProvider collectionCountProvider
*/
public function testValidationGroupViaCollectionMustSpecifyAllKeys(?int $count): void
{
$this->setCollectionCount($count);
$collection = $this->inputFilter->get('stuff');
self::assertInstanceOf(CollectionInputFilter::class, $collection);

/** @psalm-suppress InvalidArgument */
$collection->setValidationGroup([
0 => 'first',
]);

$this->inputFilter->setData([
'stuff' => [
['first' => 'Foo'],
['first' => 'Foo'],
['first' => 'Foo'],
['first' => 'Foo'],
],
]);

if (PHP_VERSION_ID >= 80000) {
$this->expectWarning();
$this->expectWarningMessage('Undefined array key 1');
} else {
$this->expectNotice();
$this->expectNoticeMessage('Undefined offset: 1');
}

$this->inputFilter->isValid();
}

/** @dataProvider collectionCountProvider */
public function testValidationGroupViaTopLevelInputFilter(?int $count): void
{
$this->setCollectionCount($count);
/** @psalm-suppress InvalidArgument */
$this->inputFilter->setValidationGroup([
'stuff' => [
0 => 'first',
1 => 'second',
2 => 'first',
3 => 'first',
],
]);

$this->inputFilter->setData([
'stuff' => [
['first' => 'Foo'],
['second' => 'Foo'],
['first' => 'Foo'],
['first' => 'Foo'],
],
]);

self::assertTrue($this->inputFilter->isValid());
}
}
78 changes: 78 additions & 0 deletions test/ValidationGroup/InputFilterStringValidationGroupTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<?php

declare(strict_types=1);

namespace LaminasTest\InputFilter\ValidationGroup;

use Laminas\InputFilter\Exception\InvalidArgumentException;
use Laminas\InputFilter\Input;
use Laminas\InputFilter\InputFilter;
use Laminas\Validator\StringLength;
use PHPUnit\Framework\TestCase;

final class InputFilterStringValidationGroupTest extends TestCase
{
private InputFilter $inputFilter;

protected function setUp(): void
{
parent::setUp();
$first = new Input('first');
$first->setRequired(true);
$first->getValidatorChain()->attach(new StringLength(['min' => 5]));
$second = new Input('second');
$second->setRequired(true);
$second->getValidatorChain()->attach(new StringLength(['min' => 5]));
$third = new Input('third');
$third->setRequired(true);
$third->getValidatorChain()->attach(new StringLength(['min' => 5]));

$this->inputFilter = new InputFilter();
$this->inputFilter->add($first);
$this->inputFilter->add($second);
$this->inputFilter->add($third);
}

public function testValidationFailsForIncompleteInput(): void
{
$this->inputFilter->setData(['first' => 'Freddy']);
self::assertFalse($this->inputFilter->isValid());
}

public function testValidationSucceedsForCompleteInput(): void
{
$this->inputFilter->setData(['first' => 'Freddy', 'second' => 'Fruit Bat', 'third' => 'Muppet']);
self::assertTrue($this->inputFilter->isValid());
}

public function testValidationSucceedsForIncompleteInputWhenValidationGroupIsProvided(): void
{
$this->inputFilter->setValidationGroup('first');
$this->inputFilter->setData(['first' => 'Freddy']);

self::assertTrue($this->inputFilter->isValid());
}

public function testThatValidationGroupIsVariadic(): void
{
$this->inputFilter->setValidationGroup('first', 'second');
$this->inputFilter->setData(['first' => 'Freddy', 'second' => 'Fruit Bat']);

self::assertTrue($this->inputFilter->isValid());
}

public function testThatValidationGroupAcceptsListOfInputNames(): void
{
$this->inputFilter->setValidationGroup(['first', 'second']);
$this->inputFilter->setData(['first' => 'Freddy', 'second' => 'Fruit Bat']);

self::assertTrue($this->inputFilter->isValid());
}

public function testValidationGroupWithUnknownInput(): void
{
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('"doughnuts" was not found');
$this->inputFilter->setValidationGroup(['doughnuts']);
}
}

0 comments on commit 89dab1f

Please sign in to comment.