mirror of
https://github.com/Respect/Validation.git
synced 2024-06-04 23:02:16 +02:00
Create "Factor" rule
This commit is contained in:
parent
748b280c34
commit
f14e53921c
19
docs/Factor.md
Normal file
19
docs/Factor.md
Normal file
|
@ -0,0 +1,19 @@
|
|||
# Factor
|
||||
|
||||
- `v::factor(int $dividend)`
|
||||
|
||||
Validates if the input is a factor of the defined dividend.
|
||||
|
||||
```php
|
||||
v::factor(0)->validate(5); //true
|
||||
v::factor(4)->validate(2); //true
|
||||
v::factor(4)->validate(3); //false
|
||||
```
|
||||
|
||||
***
|
||||
See also:
|
||||
|
||||
* [Digit](Digit.md)
|
||||
* [Finite](Finite.md)
|
||||
* [Infinite](Infinite.md)
|
||||
* [Numeric](Numeric.md)
|
27
library/Exceptions/FactorException.php
Normal file
27
library/Exceptions/FactorException.php
Normal file
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Respect/Validation.
|
||||
*
|
||||
* (c) Alexandre Gomes Gaigalas <alexandre@gaigalas.net>
|
||||
*
|
||||
* For the full copyright and license information, please view the "LICENSE.md"
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Respect\Validation\Exceptions;
|
||||
|
||||
/**
|
||||
* @author David Meister <thedavidmeister@gmail.com>
|
||||
*/
|
||||
class FactorException extends ValidationException
|
||||
{
|
||||
public static $defaultTemplates = array(
|
||||
self::MODE_DEFAULT => array(
|
||||
self::STANDARD => '{{name}} must be a factor of {{dividend}}',
|
||||
),
|
||||
self::MODE_NEGATIVE => array(
|
||||
self::STANDARD => '{{name}} must not be a factor of {{dividend}}',
|
||||
),
|
||||
);
|
||||
}
|
54
library/Rules/Factor.php
Normal file
54
library/Rules/Factor.php
Normal file
|
@ -0,0 +1,54 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Respect/Validation.
|
||||
*
|
||||
* (c) Alexandre Gomes Gaigalas <alexandre@gaigalas.net>
|
||||
*
|
||||
* For the full copyright and license information, please view the "LICENSE.md"
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use Respect\Validation\Exceptions\ValidationException;
|
||||
use Respect\Validation\Exceptions\ComponentException;
|
||||
|
||||
/**
|
||||
* @author David Meister <thedavidmeister@gmail.com>
|
||||
*/
|
||||
class Factor extends AbstractRule
|
||||
{
|
||||
public $dividend;
|
||||
|
||||
public function __construct($dividend)
|
||||
{
|
||||
if (!is_numeric($dividend) || (int) $dividend != $dividend) {
|
||||
$message = 'Dividend %s must be an integer';
|
||||
throw new ComponentException(sprintf($message, ValidationException::stringify($dividend)));
|
||||
}
|
||||
|
||||
$this->dividend = (int) $dividend;
|
||||
}
|
||||
|
||||
public function validate($input)
|
||||
{
|
||||
// Every integer is a factor of zero, and zero is the only integer that
|
||||
// has zero for a factor.
|
||||
if ($this->dividend === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Factors must be integers that are not zero.
|
||||
if (!is_numeric($input) || (int) $input != $input || $input == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$input = (int) abs($input);
|
||||
$dividend = (int) abs($this->dividend);
|
||||
|
||||
// The dividend divided by the input must be an integer if input is a
|
||||
// factor of the dividend.
|
||||
return is_integer($dividend / $input);
|
||||
}
|
||||
}
|
|
@ -55,6 +55,7 @@ use Respect\Validation\Rules\Key;
|
|||
* @method static Validator executable()
|
||||
* @method static Validator exists()
|
||||
* @method static Validator extension(string $extension)
|
||||
* @method static Validator factor(int $dividend)
|
||||
* @method static Validator false()
|
||||
* @method static Validator file()
|
||||
* @method static Validator filterVar(int $filter, mixed $options = null)
|
||||
|
|
227
tests/unit/Rules/FactorTest.php
Normal file
227
tests/unit/Rules/FactorTest.php
Normal file
|
@ -0,0 +1,227 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Respect/Validation.
|
||||
*
|
||||
* (c) Alexandre Gomes Gaigalas <alexandre@gaigalas.net>
|
||||
*
|
||||
* For the full copyright and license information, please view the "LICENSE.md"
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use Respect\Validation\Exceptions\ValidationException;
|
||||
|
||||
/**
|
||||
* @group rule
|
||||
* @covers Respect\Validation\Rules\Factor
|
||||
* @covers Respect\Validation\Exceptions\FactorException
|
||||
* @author David Meister <thedavidmeister@gmail.com>
|
||||
*/
|
||||
class FactorTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider providerForValidFactor
|
||||
*/
|
||||
public function testValidFactorShouldReturnTrue($dividend, $input)
|
||||
{
|
||||
$min = new Factor($dividend);
|
||||
$this->assertTrue($min->__invoke($input));
|
||||
$this->assertTrue($min->check($input));
|
||||
$this->assertTrue($min->assert($input));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider providerForInvalidFactor
|
||||
*/
|
||||
public function testInvalidFactorShouldThrowFactorException($dividend, $input)
|
||||
{
|
||||
$this->setExpectedException(
|
||||
'Respect\\Validation\\Exceptions\\FactorException',
|
||||
ValidationException::stringify($input).' must be a factor of '.$dividend
|
||||
);
|
||||
|
||||
$min = new Factor($dividend);
|
||||
$this->assertFalse($min->__invoke($input));
|
||||
$this->assertFalse($min->assert($input));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider providerForInvalidFactorDividend
|
||||
*/
|
||||
public function testInvalidDividentShouldThrowComponentException($dividend, $input)
|
||||
{
|
||||
$this->setExpectedException(
|
||||
'Respect\\Validation\\Exceptions\\ComponentException',
|
||||
'Dividend '.ValidationException::stringify($dividend).' must be an integer'
|
||||
);
|
||||
|
||||
// It is enough to simply create a new Factor to trigger the dividend
|
||||
// exceptions in __construct.
|
||||
new Factor($dividend);
|
||||
}
|
||||
|
||||
public function providerForValidFactor()
|
||||
{
|
||||
$tests = array(
|
||||
// Run through the first few integers.
|
||||
array(1, 1),
|
||||
array(2, 1),
|
||||
array(2, 2),
|
||||
array(3, 1),
|
||||
array(3, 3),
|
||||
array(4, 1),
|
||||
array(4, 2),
|
||||
array(4, 4),
|
||||
array(5, 1),
|
||||
array(5, 5),
|
||||
array(6, 1),
|
||||
array(6, 2),
|
||||
array(6, 3),
|
||||
array(6, 6),
|
||||
// Zero as a dividend is always a pass.
|
||||
array(0, 0),
|
||||
array(0, 1),
|
||||
array(0, mt_rand()),
|
||||
);
|
||||
|
||||
$tests = $this->generateNegativeCombinations($tests);
|
||||
|
||||
$tests = $this->generateStringAndFloatCombinations($tests);
|
||||
|
||||
return $tests;
|
||||
}
|
||||
|
||||
public function providerForInvalidFactor()
|
||||
{
|
||||
$tests = array(
|
||||
// Run through the first few integers.
|
||||
array(3, 2),
|
||||
array(4, 3),
|
||||
array(5, 2),
|
||||
array(5, 3),
|
||||
array(5, 4),
|
||||
// Zeros.
|
||||
array(1, 0),
|
||||
array(2, 0),
|
||||
);
|
||||
|
||||
$tests = $this->generateNegativeCombinations($tests);
|
||||
|
||||
$tests = $this->generateStringAndFloatCombinations($tests);
|
||||
|
||||
// Valid (but random) dividends, invalid inputs.
|
||||
$extra_tests = array_map(
|
||||
function ($test) {
|
||||
return array(mt_rand(), $test);
|
||||
},
|
||||
$this->thingsThatAreNotIntegers()
|
||||
);
|
||||
$tests = array_merge($tests, $extra_tests);
|
||||
|
||||
return $tests;
|
||||
}
|
||||
|
||||
public function providerForInvalidFactorDividend()
|
||||
{
|
||||
// Invalid dividends, valid (but random) inputs.
|
||||
$tests = array_map(
|
||||
function ($test) {
|
||||
return array($test, mt_rand());
|
||||
},
|
||||
$this->thingsThatAreNotIntegers()
|
||||
);
|
||||
|
||||
// Also check for an empty dividend string.
|
||||
$tests[] = array('', mt_rand());
|
||||
|
||||
return $tests;
|
||||
}
|
||||
|
||||
private function thingsThatAreNotIntegers()
|
||||
{
|
||||
return array(
|
||||
0.5,
|
||||
1.5,
|
||||
-0.5,
|
||||
-1.5,
|
||||
PHP_INT_MAX + 1,
|
||||
// Non integer values.
|
||||
$this->randomFloatBeweenZeroAndOne(),
|
||||
-$this->randomFloatBeweenZeroAndOne(),
|
||||
'a',
|
||||
'foo',
|
||||
// Randomish string.
|
||||
uniqid('a'),
|
||||
// Non-scalars.
|
||||
array(),
|
||||
new \StdClass(),
|
||||
new \DateTime(),
|
||||
null,
|
||||
true,
|
||||
false,
|
||||
);
|
||||
}
|
||||
|
||||
private function randomFloatBeweenZeroAndOne()
|
||||
{
|
||||
return mt_rand(1, mt_getrandmax() - 1) / mt_getrandmax();
|
||||
}
|
||||
|
||||
private function generateNegativeCombinations($tests)
|
||||
{
|
||||
// Negate all the dividends.
|
||||
$tests = array_merge(
|
||||
$tests,
|
||||
array_map(
|
||||
function ($test) {
|
||||
return array(-$test[0], $test[1]);
|
||||
},
|
||||
$tests
|
||||
)
|
||||
);
|
||||
|
||||
// Negate all the inputs.
|
||||
$tests = array_merge(
|
||||
$tests,
|
||||
array_map(
|
||||
function ($test) {
|
||||
return array($test[0], -$test[1]);
|
||||
},
|
||||
$tests
|
||||
)
|
||||
);
|
||||
|
||||
return $tests;
|
||||
}
|
||||
|
||||
private function generateStringAndFloatCombinations($tests)
|
||||
{
|
||||
$base_tests = $tests;
|
||||
|
||||
// Test everything again as a string.
|
||||
$tests = array_merge(
|
||||
$tests,
|
||||
array_map(
|
||||
function ($test) {
|
||||
return array((string) $test[0], (string) $test[1]);
|
||||
},
|
||||
$base_tests
|
||||
)
|
||||
);
|
||||
|
||||
// Test everything again as a float.
|
||||
$tests = array_merge(
|
||||
$tests,
|
||||
array_map(
|
||||
function ($test) {
|
||||
return array((float) $test[0], (float) $test[1]);
|
||||
},
|
||||
$base_tests
|
||||
)
|
||||
);
|
||||
|
||||
return $tests;
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue